2009-08-02 9 views
20

Zastanawiam się, jak ktoś powinien użyć Assert.Inconclusive().Użycie Assert.Inconclusive

Używam go, jeśli mój test jednostkowy zakończy się niepowodzeniem z innego powodu niż ten, dla którego test jest przeznaczony.

Na przykład, mam metodę na klasie, która oblicza sumę tablicy ints. W tej samej klasie istnieje również metoda obliczania średniej elementu. Jest on realizowany poprzez wywołanie sumy i podzielenie jej przez długość tablicy.

Pisanie testu jednostkowego dla Sum() jest proste. Jednak, gdy piszę test dla Average() i Sum(), nie uda się, a także Average() również się nie powiedzie.

Błąd średniej nie jest jednoznaczny z powodu niepowodzenia; nie powiodło się z powodu innego niż to, na co powinno się sprawdzić. Właśnie dlatego chciałbym sprawdzić, czy Sum() zwróci poprawny wynik, w przeciwnym razie I Assert.Inconclusive().

Czy należy to uznać za dobrą praktykę? Do czego służy Assert.Inconclusive? Czy raczej powinienem rozwiązać poprzedni przykład za pomocą Isolation Framework?

Odpowiedz

14

Kiedy używam VS do generowania testów jednostkowych, otrzymałem Assert.Inclusive dla wygenerowanych metod testowania i zwykle zmieniam asercję, więc coś innego, gdy je pracuję. Używam znaków zapytania Assert.Inconclusive w wyniku testu jako markerów, aby szybko powiedzieć mi, które testy jeszcze nie zostały zakończone.

Cóż, po prostu tak go używam. Od jego nazwy "Niekonsekwentny", myślę, że możesz użyć do wskazania swojego niezdefiniowanego stanu, o ile będziesz dokumentować, co to znaczy.

Jednakże, z opisu metody Average(), myślę, że być może twój test jednostkowy nie jest wystarczająco atomowy, aby objąć tylko jedną "jednostkę", jeden konkretny scenariusz. Czasami piszę 2 lub 3 jednostki metody testowe dla jednej metody. Możesz też złamać swoją metodę na mniejsze metody obejmujące pojedyncze obowiązki. W ten sposób możesz przetestować te mniejsze metody przed testowaniem jednostki pod numerem Average().


Johannes,

To w jaki sposób zaimplementować metody Sum() i Average().

public static class MyMath 
{ 
    private static void ValidateInput(ICollection<int> numbers) 
    { 
     if (numbers == null) 
      throw new ArgumentNullException("numbers", "Null input. Nothing to compute!"); 
     if (numbers.Count == 0) 
      throw new ArgumentException("Input is empty. Nothing to compute!"); 
    } 

    public static int Sum(int[] numbers) 
    { 
     ValidateInput(numbers); 

     var total = 0; 
     foreach (var number in numbers) 
      total += number; 

     return total; 
    } 

    public static double Average(int[] numbers) 
    { 
     ValidateInput(numbers); 
     return Sum(numbers)/numbers.Length; 
    } 
} 

Dla uproszczenia, po prostu rzucać ArgumentException wyjątki od metody ValidateInput(ICollection<int>). Możesz również sprawdzić, czy nie ma możliwości przepełnienia i wrzucenia metody OverflowException w metodzie.

Powiedziawszy, oto jak przetestować funkcję Average(int[]).

[TestMethod] 
public void AverageTest_GoodInput() 
{ 
    int[] numbers = {1, 2, 3}; 
    const double expected = 2.0; 
    var actual = MyMath.Average(numbers); 
    Assert.AreEqual(expected, actual); 
} 

[TestMethod] 
[ExpectedException(typeof(ArgumentNullException))] 
public void AverageTest_NullInput() 
{ 
    int[] numbers = null; 
    MyMath.Average(numbers); 
} 

[TestMethod] 
[ExpectedException(typeof(ArgumentException))] 
public void AverageTest_EmptyInput() 
{ 
    var numbers = new int[0]; 
    MyMath.Average(numbers); 
} 

Dzięki tym ustawieniom testów mogę być pewien, że po przejściu wszystkich testów moja funkcja jest poprawna. Cóż, z wyjątkiem przypadku przepełnienia. Teraz mogę wrócić do metody ValidateInput(ICollection<int>), aby dodać logikę w celu sprawdzenia nadmiaru, a następnie dodać jeszcze jeden test, aby oczekiwać wyrzucenia OverflowException dla tego rodzaju danych wejściowych, które powodują przepełnienie. Lub robisz to w odwrotnej kolejności, jeśli chcesz podejść do używania TDD.

Mam nadzieję, że pomoże to wyjaśnić pomysł.

+0

. Czy mógłbyś wyjaśnić, jak podejść do tego w tym szczególnym przypadku? –

+0

Dziękuję bardzo. więc w istocie mówisz, że nie ma potrzeby pisania wyraźnego testu dla Sum(), ale testowanie go przez Average(). Z perspektywy pokrycia kodu generuje to ten sam wynik. –

+1

Chciałbym również napisać testy dla Sum(). Kto wie w mojej śpiącej chwili, mógłbym wpisać "-" zamiast "/". :) Z testami dla Sum() w miejscu, jeśli dostałem wszystkie testy dla Pass(), ale niektóre testy dla Average() zawodzą, mogę być pewny, że implementacja dla Average() jest błędna. Nie będę w stanie winić Sum(), że spowodowało, że średnia() jest zła. :) – tranmq

9

Tylko Assert.Inconclusive na testy jednostkowe, których jeszcze nie napisałem. Czasem, gdy coś piszę, zdaję sobie sprawę z jakiegoś rogu, którego nie chcę przegapić. Dlatego szybko przeskakuję, napisz metodę testową z opisową nazwą i dodaj pojedynczą linię Assert.Inconclusive.

Powodem tego jest dostarczenie dokumentacji na temat rzeczy, które muszę przetestować, bez przerywania pracy. Umożliwia to również szybkie odfiltrowanie błędów testowych na liście wyników. Posiadanie nierozstrzygającej porażki oznacza, że ​​nie złamałem niczego, po prostu więcej testów do napisania.

+1

Kilka komentarzy: (1) Visual Studio uważa, że ​​testy, które są niejednoznaczne, są "pomijanymi testami" w Eksploratorze testów. Ta kategoria staje się następnie twoją listą rzeczy do zrobienia. Jared już wspomniał o tym z "filtrowaniem błędów testowych", ale widzę, że jest to duża korzyść (2) Jeśli masz kilka asercji w jednym teście (to zdanie), ale twierdzisz, że nie jest to jednoznaczne, cały test jest uznany za "pomijany" . " Wcześniej używałem niejednoznacznych do przedstawiania tej samej sytuacji co Dennis C, ale teraz nie lubię tego, ponieważ nie jest jasne, jaki jest ogólny wynik testu. – DPH

23

Nie rozstrzygający test jest testem, dla którego nie można określić wyniku. Na przykład, jeśli masz test, który korzysta z jakiegoś zewnętrznego zasobu (na przykład połączenie z Internetem). Jeśli połączenie nie jest obecnie dostępne, nie oznacza to, że test jest niepowodzeniem. Z drugiej strony, nie powinieneś oznaczyć go jako udanego, nie przepuszczając go. Oznacza to, że jest to niejednoznaczne i można to zaobserwować w raporcie z badań.

UWAGA: Zasadniczo nie należy korzystać z takich zewnętrznych zasobów w swoich testach, ponieważ może to spowodować, że testy będą kruche.

Do testów, które nie zostały jeszcze zakończone, używam atrybutu MbUnit o wartości Explicit.

+2

Użyłem Niekonkurencyjnego w e-mailu, by anulować. Kod wysyła wiadomości e-mail, a ja muszę sprawdzić układ graficzny ze skrzynki pocztowej programu Outlook –

7

Assert.Inconclusive wskazuje, że:

ja jeszcze nie napisany test; mam tylko stworzył metodę testową

-lub-

Mój testowy ma zależność i że zależność jest niedostępne. Na przykład:

List<Customer> custs = o.GetAllCustomers(); 
if (custs.Count == 0) 
{ 
    Assert.Inconclusive("No customers to test"); 
    return; 
}