Testy jednostkowe: odroczone twierdzenia z Linq

18

Czy można dodawać odroczone twierdzenia w ten sposób?

var actualKittens = actualKittens.Select(kitten => {
    Assert.IsСute(kitten);
    return kitten
});

Dlaczego? Mogę więc powtórzyć tylko raz, nawet w przypadku stwierdzeń oczekujących zmaterializowanej kolekcji, na przykład:

CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

Może to być nie tylko Select, ale metoda ze zdefiniowanym iteratorem i mająca wiele kontroli i logiki (np. Zliczanie i filtrowanie).

Nasieniem wątpliwości jest złożoność odczytu i debugowania takiego kodu w przypadku niepowodzenia testu.

SerG
źródło
1
I nie będzie polegać na tym do testowania ale czasami OK, aby zrobić to w kodzie produkcji, jeśli nie ma lepszego rozwiązania. Możesz zrobić sobie funkcję pomocnika, sequence.WithSideEffect(item => Assert.IsCute(item))aby uczynić go czystszym.
usr
@usr Wygląda na to, że złapałeś kluczową wadę takiego sposobu - efekt uboczny z iteratora.
SerG
Czy nadal nie musisz powtarzać dwa razy, raz, aby wygenerować listę i jeszcze raz, aby ją porównać expectedKittens? Właśnie ukryłeś iteracje wywołań metod.
IllusiveBrian
@IllusiveBrian W tym sensie w przykładzie tak. To wciąż mniej niż z dodatkowymi .All().
SerG

Odpowiedzi:

37

Czy można dodawać odroczone twierdzenia takie jak ten [..]

Nie , nie jest. Dlaczego? Ponieważ jeśli z jakiegokolwiek powodu usuniesz drugie stwierdzenie, test nadal zmieni kolor na zielony i uważasz, że nadal działa, ale nie działa, ponieważ kolekcja nie zostanie wyliczona. Jeśli masz dwa lub więcej niezależnych stwierdzeń, będą wykonywać swoją pracę nawet po wyłączeniu jednego z nich.

Rozważ tę kombinację:

Assert.IsTrue(actualKittens.All(x => x.IsCute());
CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

Teraz nawet jeśli wyłączysz lub usuniesz jeden z twierdzeń, drugi nadal wykona swoją pracę. Również jeśli zapomnisz zmaterializować kolekcję, jej uruchomienie może potrwać dłużej, ale nadal będzie działać. Niezależne testy są bardziej niezawodne i niezawodne.

Jest też drugie nie . Nie jestem pewien, jak radzą sobie z tym inne frameworki, ale jeśli używasz platformy MS Test, nie wiedziałbyś, który test się nie powiódł. Jeśli klikniesz dwukrotnie test zakończony niepowodzeniem, wyświetli się komunikat „zakończony CollectionAssertniepowodzeniem”, ale w rzeczywistości zagnieżdżenie się nie powiodło Asserti bardzo trudno będzie go debugować. Oto przykład:

    [TestMethod]
    public void TestMethod()
    {
        var numbers = new[] { 1, 2, 3 }.Select(x =>
        {
            Assert.Fail("Wrong number.");
            return x;
        });

        // This will fail and you won't be sure why.
        CollectionAssert.AreEqual(new[] { 1, 2, 3 }, numbers.ToList()); 

    }

Oznacza to, że pierwszy test jest faktycznie bezużyteczny, ponieważ nie pomaga znaleźć błędu. Nie wiesz, czy nie powiódł się, ponieważ numer był nieprawidłowy lub ponieważ obie kolekcje były różne.


Dlaczego? Mogę więc powtórzyć tylko raz, nawet z oświadczeniami oczekującymi zmaterializowanej kolekcji

Zastanawiam się, dlaczego ci na tym zależy? To są testy jednostkowe. Nie musisz optymalizować każdego z nich i zwykle testy nie wymagają milionów elementów, więc wydajność nie powinna być problemem.

Musisz utrzymywać takie testy, więc dlaczego miałbyś je bardziej skomplikować niż to konieczne? Napisz proste stwierdzenia, które działają.

t3chb0t
źródło
Jeśli z jakiegoś powodu asercja musi zostać zakopana w przepływie sterowania, jednym ze sposobów upewnienia się, że została wykonana, jest zachowanie licznika / flagi, która jest zwiększana / ustawiana na wartość true przed zagnieżdżeniem asercji. Później możemy stwierdzić, że oczekiwany przepływ kontrolny został przejęty przez sprawdzenie tego licznika. Nie idealnie, ale w dużej mierze odnosi się do twojej pierwszej krytyki.
amon
1
Ponadto ty lub ktoś inny powróci do odroczonego twierdzenia za 6 miesięcy i będziesz musiał tracić czas na jego rozpracowanie.
DavidTheWin
Coś jest nie tak z twoim przykładem. Wywołanie ToListspowoduje iterację tego, co wyliczalne, prawda?
RubberDuck,
1
@RubberDuck tak, to się powiedzie i również zawiedzie, ale nie na, Assert.Failale na CollectionAsserti nie będziesz w stanie powiedzieć, które twierdzenie faktycznie poszło nie tak. Mam na myśli, że VS nie skupi się Assert.Failna innym, ale na drugim ... teraz możesz debugować.
t3chb0t