2009-03-05 12 views
15

Czytałem o testowaniu jednostkowym i słyszałem wiele hullabaloo przez innych, zachwalających jego użyteczność i chciałbym zobaczyć to w akcji. W związku z tym wybrałem tę podstawową klasę z prostej aplikacji, którą utworzyłem. Nie mam pojęcia, w jaki sposób testy mogłyby mi pomóc, i mam nadzieję, że jeden z was będzie w stanie pomóc mi dostrzec zalety tego, wskazując, które części tego kodu można przetestować i jak te testy mogą wyglądać. Jak więc napisać testy jednostkowe dla następującego kodu?Praktyczne przykłady Testowanie kodu C#

public class Hole : INotifyPropertyChanged 
{ 
    #region Field Definitions 
    private double _AbsX; 
    private double _AbsY; 
    private double _CanvasX { get; set; } 
    private double _CanvasY { get; set; } 
    private bool _Visible; 
    private double _HoleDia = 20; 
    private HoleTypes _HoleType; 
    private int _HoleNumber; 
    private double _StrokeThickness = 1; 
    private Brush _StrokeColor = new SolidColorBrush(Colors.Black); 
    private HolePattern _ParentPattern; 
    #endregion 

    public enum HoleTypes { Drilled, Tapped, CounterBored, CounterSunk }; 
    public Ellipse HoleEntity = new Ellipse(); 
    public Ellipse HoleDecorator = new Ellipse(); 
    public TextBlock HoleLabel = new TextBlock(); 

    private static DoubleCollection HiddenLinePattern = 
       new DoubleCollection(new double[] { 5, 5 }); 

    public int HoleNumber 
    { 
     get 
     { 
      return _HoleNumber; 
     } 
     set 
     { 
      _HoleNumber = value; 
      HoleLabel.Text = value.ToString(); 
      NotifyPropertyChanged("HoleNumber"); 
     } 
    } 
    public double HoleLabelX { get; set; } 
    public double HoleLabelY { get; set; } 
    public string AbsXDisplay { get; set; } 
    public string AbsYDisplay { get; set; } 

    public event PropertyChangedEventHandler PropertyChanged; 
    //public event MouseEventHandler MouseActivity; 

    // Constructor 
    public Hole() 
    { 
     //_HoleDia = 20.0; 
     _Visible = true; 
     //this.ParentPattern = WhoIsTheParent; 
     HoleEntity.Tag = this; 
     HoleEntity.Width = _HoleDia; 
     HoleEntity.Height = _HoleDia; 

     HoleDecorator.Tag = this; 
     HoleDecorator.Width = 0; 
     HoleDecorator.Height = 0; 


     //HoleLabel.Text = x.ToString(); 
     HoleLabel.TextAlignment = TextAlignment.Center; 
     HoleLabel.Foreground = new SolidColorBrush(Colors.White); 
     HoleLabel.FontSize = 12; 

     this.StrokeThickness = _StrokeThickness; 
     this.StrokeColor = _StrokeColor; 
     //HoleEntity.Stroke = Brushes.Black; 
     //HoleDecorator.Stroke = HoleEntity.Stroke; 
     //HoleDecorator.StrokeThickness = HoleEntity.StrokeThickness; 
     //HiddenLinePattern=DoubleCollection(new double[]{5, 5}); 
    } 

    public void NotifyPropertyChanged(String info) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, 
         new PropertyChangedEventArgs(info)); 
     } 
    } 

    #region Properties 
    public HolePattern ParentPattern 
    { 
     get 
     { 
      return _ParentPattern; 
     } 
     set 
     { 
      _ParentPattern = value; 
     } 
    } 

    public bool Visible 
    { 
     get { return _Visible; } 
     set 
     { 
      _Visible = value; 
      HoleEntity.Visibility = value ? 
      Visibility.Visible : 
      Visibility.Collapsed; 
      HoleDecorator.Visibility = HoleEntity.Visibility; 
      SetCoordDisplayValues(); 
      NotifyPropertyChanged("Visible"); 
     } 
    } 

    public double AbsX 
    { 
     get { return _AbsX; } 
     set 
     { 
      _AbsX = value; 
      SetCoordDisplayValues(); 
      NotifyPropertyChanged("AbsX"); 
     } 
    } 

    public double AbsY 
    { 
     get { return _AbsY; } 
     set 
     { 
      _AbsY = value; 
      SetCoordDisplayValues(); 
      NotifyPropertyChanged("AbsY"); 
     } 
    } 

    private void SetCoordDisplayValues() 
    { 
     AbsXDisplay = HoleEntity.Visibility == 
     Visibility.Visible ? String.Format("{0:f4}", _AbsX) : ""; 
     AbsYDisplay = HoleEntity.Visibility == 
     Visibility.Visible ? String.Format("{0:f4}", _AbsY) : ""; 
     NotifyPropertyChanged("AbsXDisplay"); 
     NotifyPropertyChanged("AbsYDisplay"); 
    } 

    public double CanvasX 
    { 
     get { return _CanvasX; } 
     set 
     { 
      if (value == _CanvasX) { return; } 
      _CanvasX = value; 
      UpdateEntities(); 
      NotifyPropertyChanged("CanvasX"); 
     } 
    } 

    public double CanvasY 
    { 
     get { return _CanvasY; } 
     set 
     { 
      if (value == _CanvasY) { return; } 
      _CanvasY = value; 
      UpdateEntities(); 
      NotifyPropertyChanged("CanvasY"); 
     } 
    } 

    public HoleTypes HoleType 
    { 
     get { return _HoleType; } 
     set 
     { 
      if (value != _HoleType) 
      { 
       _HoleType = value; 
       UpdateHoleType(); 
       NotifyPropertyChanged("HoleType"); 
      } 
     } 
    } 

    public double HoleDia 
    { 
     get { return _HoleDia; } 
     set 
     { 
      if (value != _HoleDia) 
      { 
       _HoleDia = value; 
       HoleEntity.Width = value; 
       HoleEntity.Height = value; 
       UpdateHoleType(); 
       NotifyPropertyChanged("HoleDia"); 
      } 
     } 
    } 

    public double StrokeThickness 
    { 
     get { return _StrokeThickness; } 
     //Setting this StrokeThickness will also set Decorator 
     set 
     { 
      _StrokeThickness = value; 
      this.HoleEntity.StrokeThickness = value; 
      this.HoleDecorator.StrokeThickness = value; 
      NotifyPropertyChanged("StrokeThickness"); 
     } 
    } 

    public Brush StrokeColor 
    { 
     get { return _StrokeColor; } 
     //Setting this StrokeThickness will also set Decorator 
     set 
     { 
      _StrokeColor = value; 
      this.HoleEntity.Stroke = value; 
      this.HoleDecorator.Stroke = value; 
      NotifyPropertyChanged("StrokeColor"); 
     } 
    } 

    #endregion 

    #region Methods 

    private void UpdateEntities() 
    { 
     //-- Update Margins for graph positioning 
     HoleEntity.Margin = new Thickness 
     (CanvasX - HoleDia/2, CanvasY - HoleDia/2, 0, 0); 
     HoleDecorator.Margin = new Thickness 
     (CanvasX - HoleDecorator.Width/2, 
     CanvasY - HoleDecorator.Width/2, 0, 0); 
     HoleLabel.Margin = new Thickness 
     ((CanvasX * 1.0) - HoleLabel.FontSize * .3, 
     (CanvasY * 1.0) - HoleLabel.FontSize * .6, 0, 0); 
    } 

    private void UpdateHoleType() 
    { 
     switch (this.HoleType) 
     { 
      case HoleTypes.Drilled: //Drilled only 
       HoleDecorator.Visibility = Visibility.Collapsed; 
       break; 
      case HoleTypes.Tapped: // Drilled & Tapped 
       HoleDecorator.Visibility = (this.Visible == true) ? 
       Visibility.Visible : Visibility.Collapsed; 
       HoleDecorator.Width = HoleEntity.Width * 1.2; 
       HoleDecorator.Height = HoleDecorator.Width; 
       HoleDecorator.StrokeDashArray = 
       LinePatterns.HiddenLinePattern(1); 
       break; 
      case HoleTypes.CounterBored: // Drilled & CounterBored 
       HoleDecorator.Visibility = (this.Visible == true) ? 
       Visibility.Visible : Visibility.Collapsed; 
       HoleDecorator.Width = HoleEntity.Width * 1.5; 
       HoleDecorator.Height = HoleDecorator.Width; 
       HoleDecorator.StrokeDashArray = null; 
       break; 
      case HoleTypes.CounterSunk: // Drilled & CounterSunk 
       HoleDecorator.Visibility = (this.Visible == true) ? 
       Visibility.Visible : Visibility.Collapsed; 
       HoleDecorator.Width = HoleEntity.Width * 1.8; 
       HoleDecorator.Height = HoleDecorator.Width; 
       HoleDecorator.StrokeDashArray = null; 
       break; 
     } 
     UpdateEntities(); 
    } 

    #endregion 

} 

Odpowiedz

1

Oto przykład. Pamiętaj, Twój kod przykładowy brakowało definicji dla liczby zależności:

[TestFixture()] 
public class TestHole 
{ 

    private Hole _unitUnderTest; 

    [SetUp()] 
    public void SetUp() 
    { 
     _unitUnderTest = new Hole(); 
    } 

    [TearDown()] 
    public void TearDown() 
    { 
     _unitUnderTest = null; 
    } 

    [Test] 
    public void TestConstructorHole() 
    { 
     Hole testHole = new Hole(); 
     Assert.IsNotNull(testHole, "Constructor of type, Hole failed to create instance."); 
    } 

    [Test] 
    public void TestNotifyPropertyChanged() 
    { 
     string info = null; 
     _unitUnderTest.NotifyPropertyChanged(info); 
    } 
} 

Można zobaczyć, że testuje że konstruktor produkuje ważny obiekt (zazwyczaj nie jest konieczne z pełnym badawczym w miejscu budowy jest zwykle dobrze ćwiczony) i testuje również jedyną publiczną metodę w klasie. W takim przypadku będziesz potrzebował delegata obsługi zdarzeń i Assert, aby sprawdzić zawartość parametru info.

Celem jest napisanie testów, które wykorzystują każdą metodę twojej klasy. Zwykle obejmuje to ograniczenia górne i dolne oraz warunki awaryjne.

4

Nie można poprawnie przetestować tego kodu, chyba że podano również specyfikację. "Testowanie" oznacza na ogół upewnienie się, że oprogramowanie działa zgodnie z projektem.

EDYCJA: To naprawdę nie jest odpowiedź "wyloguj". Pracowałem już jako tester i mogę powiedzieć, że prawie wszystkie przypadki testowe, które napisałem, pochodziły bezpośrednio ze specyfikacji oprogramowania.

+0

Pokonuje jedno miejsce, w którym pracowałem, gdzie testy zostały utworzone przez programistę zgodnie z pomysłem autora specyfikacji. Zawsze czułem, że oszukuję, robiąc własne testy. –

+0

Tworzenie własnych testów nie jest oszustwem. Mówią, że rozumieliście specyfikację i byli w stanie podzielić ją na komponenty, które w całości są tym, czego chce konsument oprogramowania. – flq

0

jeden przykład,

dla

HoleTypes publicznych HoleType

test/sprawdzić dla wartości null w zestawie

6

jednostka testowa Przykład:

  • zweryfikować, PropertyChanged Event jest uruchamiany z poprawnymi argami zdarzenia. Użyj refleksji w teście, aby powtórzyć wszystkie właściwości ustawiając wartości i sprawdzając zdarzenie.

Zwykle odbywa się to za pomocą architektury testowej, takiej jak NUnit.

(zabawne przyczyny można zauważyć, że nieruchomość ParentPattern nie ognia zdarzenie.)

+0

Testy wykorzystujące odbicie nie są tak dobre. Dla mnie wskazują na pewne problemy z projektowaniem. Poza tym takie testy najprawdopodobniej ulegną zerwaniu i są dość niejasne. –

+0

Nie jestem testującym profesjonalistą, ale nadal nie mogę znaleźć dobrego sposobu na zautomatyzowanie testów jednostkowych niezależnie od tego, czy zdarzenie się pojawi. –

+0

Reflection pozwala zapomnieć o tym teście po jego zakodowaniu. W tym przykładzie testowaliśmy, że zdarzenie jest uruchamiane, gdy właściwość zmienia się na tym podmiocie. Czy nowy twórca myśli, że powróci do testu po dodaniu nowej nieruchomości? Czy test jest nadal zielony, jeśli nie testuje wszystkich właściwości? – Gord

2

Badanie to nie tylko technika - to sztuka. Coś, co wymaga przeczytania. Nie jestem pewien, czy będzie możliwe nauczenie cię przez to jedno pytanie, wszystko, co chcesz/potrzebujesz/powinno/powinno/musisz wiedzieć. Aby rozpocząć, oto kilka rzeczy, które możesz przetestować.

  • jednostkowa (interfejsy działać zgodnie z oczekiwaniami)
  • Integration (komponenty zachowują się między sobą)
  • Użyteczność (klienci są zadowoleni)
  • funkcjonalna (funkcja kompletne)

definiują zestaw kryteria dla każdego (metryki) i rozpocząć testowanie.

+0

To nie jest sztuka. Może być artystyczne, ale nie sztuką. – OscarRyz

+0

Patrzę na inżynierię jako beztłuszczową formę sztuki. – dirkgently

+0

To może być powód. W moim przypadku myślę, że sztuka nie ma innego celu niż "odtworzenie" człowieka. Jeśli twój kod (lub cokolwiek innego) główny cel jest inny niż ten, to nie jest sztuka (dla mnie). Na przykład testowanie pierwszego celu to sprawdzanie poprawności oprogramowania. :) :) Pokój. – OscarRyz

1

Np. Wydaje się, że większość tej klasy nie musi być testowana (poza Gord's answer), jeśli klasa została napisana w inny sposób. Na przykład mieszane są informacje o modelu (typ, itp.) Z informacjami o widoku (grubości). Ponadto, myślę, że brakuje punktu WPF i databinding/wyzwalaczy. UpdateHoleType() Powinien być wyrażony w pliku .xaml jako zestaw DataTriggers, a tak samo w UpdateEntities() i większości innych posiadanych właściwości.

+0

+1 za wskazanie połączenia informacji "model" i "widok". (Myślałem o tym również, ale nie w stylu MVC.) – strager

2

W testowaniu jednostkowym wystarczy przetestować swoje "widoczne" metody/właściwości, a nie prywatne.

Tak na przykład w kodzie można dodać następujące testy: „dobrze ów oczywistej

hole.Visible = false; 

Debug.Assert("".Equals(hole.AbsXDisplay)); 
Debug.Assert("".Equals(hole.AbsYDisplay)); 

Można by pomyśleć, ale po kilku tygodniach możesz o tym zapomnieć. A jeśli jakaś część twojego kodu zależy od wartości AbsXDisplay (która jest atrybutem publicznym) i z jakiegoś powodu po ustawieniu właściwości na false, nie jest to już "", ale "puste" lub "NotSet", to test się nie powiedzie i zostaniesz o tym natychmiast powiadomiony.

Powinieneś to zrobić dla każdej publicznej metody lub atrybutu, który zawiera w sobie pewną regułę biznesową lub która dotyczy innej części twojej klasy.

Niektórzy ludzie uważają, łatwiejsze do testowania pierwszy (i zrobić test fail), a następnie kod spełniające warunki, w ten sposób można kod tylko co testować i przetestować tylko to, co cię to obchodzi (szukaj TDD)

To był tylko prosty przykład tego, co możesz zrobić, aby przetestować swój kod.

Mam nadzieję, że pomoże ci to dobrze zrozumieć, o co chodzi w tym teście.

Jak sugerowali inni, poszukaj schematu testowego.

+0

Istnieje wartość w testowaniu prywatnych metod. "Glassbox" kontra "blackbox". Często możesz napisać węższy, ostrzejszy, prostszy, bardziej odkrywczy test, testując prywatnie niż publicznie. Testy szklane muszą zostać zmienione, gdy prywatne metody się zmieniają, ale jest to część zwykłego refaktoryzacji. – Schwern

-1

Cóż, historia zaczyna się od teorii.

Oto, co zrobiłem.

Po pierwsze, jeśli programujesz w języku OO, poznaj wzorce projektowe. Jest to najłatwiejsze, jeśli tworzysz grupę analityczną i uczysz się razem z przyjaciółmi i współpracownikami.

Poświęć kilka miesięcy na łatwe trawienie wszystkich wzorów.

Następnie przejdź do technik refaktoryzacji, w których dowiesz się, jak przekształcić dowolny kod na kod, który będzie wykorzystywał wcześniej nauczone bloki, np. wzorce projektowe.

Po tym przygotowaniu testy będą tak łatwe, jak każda inna technika programowania.

+0

Wszystkie oprócz najprostszych refaktur REQUIRE testing! I tylko jeśli nauczysz się wzorców jako ćwiczeń rutynowych, będą one ograniczone do języków OO. Ta kolejność jest okropna. Testowanie, refaktoryzacja i wzorce należy nauczyć się równolegle z naciskiem na testowanie. OO jest w zupełnie innym zestawie. – Schwern

+0

@Schwern Masz całkowitą rację. Mówiłem ściśle o tym, jak nauczyłem się testować. Problem polega na ładowaniu początkowym. Jak zacząć? Czego można się nauczyć na początku? Musisz zacząć od czegoś, nie musisz –

4

Powiem ci wielką tajemnicę testowania.

Podczas pisania testu piszesz oprogramowanie, które sprawdza inne oprogramowanie. Sprawdza, czy twoje założenia są prawdziwe. Twoje założenia są po prostu oświadczeniami. Oto głupi prosty test, który działa.

if(1 + 1 == 2) { 
    print "ok - 1 plus 1 equals 2\n"; 
} 
else { 
    print "not ok\n"; 
} 

Te stwierdzenia, te twierdzenia muszą być prawdziwe, ponieważ istnieje błąd lub brak funkcji. Powoduje to zauważenie błędów szybciej, zanim staną się owłosionymi, systematycznymi błędami, zanim użytkownik je zobaczy. Awaria wskazuje na problem, który należy rozwiązać. Idealnie, daje również wystarczającą ilość informacji do zdiagnozowania problemu. Skoncentrowany test i diagnostyka znacznie przyspieszają debugowanie.

Piszecie to oprogramowanie, aby wykonać pracę za Ciebie. Aby zrobić to lepiej niż możesz. Możesz przetestować oprogramowanie ręcznie, przyglądając się wynikom, ale testy po zapisaniu nie znikną. Budują i budują i budują, aż pojawi się ogromna masa testujących nowe funkcje, stare funkcje, nowe błędy i stare błędy. Zadanie ręcznego testowania nowego kodu, a także upewnienia się, że nie przywróciłeś jakiegoś starego błędu, szybko staje się przytłaczające. Człowiek po prostu przestanie testować stare błędy. Zostaną one przywrócone, a czas zostanie zmarnowany. Program testowy może zrobić to wszystko za naciśnięciem jednego przycisku. Jest to nudne, rutynowe zadanie. Ludzie ssają je, dlatego wynaleźliśmy komputery. Pisząc oprogramowanie, aby przetestować swoje oprogramowanie, używasz komputera do tego, do czego był przeznaczony: oszczędzając czas.

Ujmę to w uproszczony sposób, ponieważ ludzie, którzy są nowi w testowaniu, często są przytłoczeni. Myślą, że jest jakaś magia. Niektóre specjalne ramy, z których muszą korzystać. Często nawet zapominają, że testy wciąż są programami i nagle nie mogą myśleć o użyciu pętli lub napisaniu podprogramu. Jest o wiele więcej do nauczenia się, ale mam nadzieję, że da ci to jądro, na którym można się zorientować, co to jest "test".

+1

Trochę za dużo wędrówek, ale wciąż dobra odpowiedź. – strager

0

Musimy to przetestować, prawda?

Testy potwierdzają, że kod działa zgodnie z oczekiwaniami. W tej chwili pisanie testów dla tej klasy nie przyniesie żadnych rzeczywistych korzyści (chyba że odkryjesz błąd podczas pisania testów). Prawdziwą korzyścią jest to, kiedy będziesz musiał wrócić i zmodyfikować tę klasę. Możesz używać tej klasy w kilku różnych miejscach w swojej aplikacji. Bez testów zmiany w klasie mogą mieć nieprzewidziane przypadki. Dzięki testom możesz zmienić klasę i mieć pewność, że nie przerwiesz czegoś innego, jeśli przejdą wszystkie twoje testy. Oczywiście testy muszą być dobrze napisane i obejmować całą funkcjonalność klasy.

Jak to przetestować?

Na poziomie klasy należy pisać testy jednostkowe. Istnieje kilka frameworków testów jednostkowych. Wolę NUnit.

Co testuję?

Testujesz, że wszystko zachowuje się tak, jak oczekujesz od niego. Jeśli podasz metodę X, możesz oczekiwać, że Y zostanie zwrócona. W odpowiedzi na Gord's zasugerował testowanie, że twoje wydarzenie faktycznie odpala. To byłby dobry test.

Książka, Agile Principles, Patterns, and Practices in C# autorstwa wujka Boba naprawdę pomogła mi zrozumieć, co i jak przetestować.

1

Przez testowanie przyjmuję, że chodzi o projektowanie sterowane testami. Projektowanie oparte na testach dotyczy głównie testów jednostkowych i czasami testów integracyjnych. Testy jednostkowe testują najmniejsze kodowalne elementy kodu, a testy integracji testują interakcję między komponentami z aplikacją.

Istnieje wiele innych form testowania, ale to właśnie one zazwyczaj robią same. W innych testach najczęściej sprawdza się aplikację przed i testuje interfejsy użytkownika narażone na różne jakości, takie jak poprawność, wydajność i skalowalność.

Testowanie jednostek polega na przetestowaniu metod, aby sprawdzić, czy robią to, co chcesz. Zazwyczaj są to testy tak proste, że niemal można by pomyśleć, że są trywialne. To, czego chcesz przetestować, to logika twojej klasy. Klasa, którą zapewniasz, nie ma tak naprawdę logiki.

Tylko wersja private void UpdateHoleType(){...} zawiera dowolną logikę, która wydaje się być logiką zorientowaną wizualnie, zawsze najtrudniejszą do przetestowania. Pisanie testów jest bardzo proste. Poniżej znajduje się przykład dla wierconego holetypu.

[Test] 
public void testDrilledHole() 
{ 
    Hole hole = new Hole(); 
    hole.HoleType = HoleTypes.Drilled; 
    Assert.AreEqual(Visibility.Collapsed, hole.HoleDecorator.Visibility); 
} 

Jeśli spojrzysz na to, prawie nie uznasz tego za warte. Test jest banalny i oczywisty. Atrybut [Test] deklaruje metodę jako test, a metoda Assert.AreEquals() generuje wyjątek, jeśli podane wartości nie są równe. Rzeczywisty konstrukt może się różnić w zależności od użytej ramki testowej, ale wszystkie są równie proste.

W tym przypadku piszesz te metody dla wszystkich metod w klasie, wykonując logikę biznesową i testując wiele wartości. null zawsze warto spróbować.

Moc testów jednostkowych polega na połączeniu wszystkich tych testów. Teraz, jeśli zmienisz coś w klasie, istnieje szereg testów sprawdzających, czy wprowadzona zmiana złamie jedno z zachowań, które zdefiniowałeś w teście. Pozwala to na pracę z większym projektem, zmianę i implementację nowych funkcji, podczas gdy testy zachowują funkcjonalność, którą już zakodowałeś.

1

Testy pomogą, jeśli zajdzie potrzeba wprowadzenia zmian.

Zgodnie z piór (pióra, Working Effectively with Legacy Code, str. 3) istnieją cztery powody zmian:

  • Dodawanie funkcji
  • Fixing błąd
  • poprawy projektowania
  • wykorzystania zasobów Optymalizacja

Gdy zachodzi potrzeba zmiany, chcesz mieć pewność, że nie złamiesz anythi ng. Mówiąc dokładniej: nie chcesz łamać żadnego zachowania (Hunt, Thomas, Pragmatic Unit Testing in C# with NUnit, s. 31).

Dzięki testom jednostkowym można wprowadzać zmiany z większą pewnością, ponieważ (o ile są one odpowiednio zaprogramowane) rejestrują zmiany w zachowaniu. To zaleta testów jednostkowych.

Trudno byłoby wykonać testy jednostkowe dla klasy, którą podałeś jako przykład, , ponieważ testy jednostkowe również wymagają określonej struktury testowanego kodu. Jednym z powodów, dla którego widzę, jest to, że klasa robi zbyt wiele. Wszelkie testy jednostkowe, które zastosujesz na tej klasie, będą dość kruche. Drobne zmiany mogą spowodować, że twoje testy jednostek wybuchną, a skończy się to marnowaniem czasu na rozwiązywanie problemów w kodzie testowym zamiast w kodzie produkcyjnym.

Aby czerpać korzyści z testów jednostkowych, należy zmienić kod produkcyjny.Po prostu zastosowanie zasad testów jednostkowych, bez uwzględnienia tego nie da pozytywnego doświadczenia z testowaniem jednostek.

Jak uzyskać pozytywny wynik testu jednostkowego? Bądź otwarty na to i naucz się.

Polecam Ci Working Effectively with Legacy Code dla istniejącej podstawy kodu (jak ten fragment kodu, który podałeś powyżej). Aby łatwo rozpocząć testowanie jednostkowe, wypróbuj Pragmatic Unit Testing in C# with NUnit. Prawdziwy otwieracz do oczu dla mnie był xUnit Test Patterns: Refactoring Test Code.

Powodzenia w podróży!

0

chodzi o imprezy Zawiadom wypalania cię z pewnością powinny upewnić, czy klasa pracuje zgodnie ze specyfikacją, a mianowicie, że:

  • Dominująca będzie nigdy ogień, niezależnie od wartości ustawionej
  • StrokeColour i StrokeThickness zawsze pożaru impreza, mimo że sama wartość jest ustawiona
  • CanvasX/Y, tylko HoleType/Dia ogień, gdy wartość różni się od poprzedniej jest ustawiony

Wtedy y Chcesz sprawdzić kilka efektów ubocznych, które powodują ustawienie właściwości. Po tym można pomyśleć o refaktoryzacji, ponieważ, dang, to nie jest ładna klasa!

Powiązane problemy