Czytelne testy z FluentAssertions
FluentAssertions
FluentAssertions jest biblioteką, dzięki której assercje w testach są dużo bardziej czytelne. Osobiście używam jej, jeśli tylko mogę. Assercje z jej wykorzystaniem są łatwe do zrozumienia, a i komunikaty błędów są moim zdaniem czytelniejsze, niż w przypadku standardowych assercji.
Instalacja w projekcie
Bibliotekę FluentAssertions można zainstalować z Nuget-a, wybierając manage nuget package z menu kontekstowego na referencjach projektu testowego
lub poprzez Package Manager Console (zwrócić należy uwagę, żeby wygrać odpowiedni projekt w konsoli) z wykorzystaniem polecenia:
1 |
Install-Package FluentAssertions |
Pierwsze Kroki
FluentAssertions jako główny komponent wykorzystuje extension method, który to pobiera nasz obiekt, na którym chcemy wykonać porównanie i tworzy nam obiekt assercji. Takie połączenie jest dla mnie wygodniejsze, niż wykorzystywanie statycznych metod z klasy Assert.
Zapis assercji zawsze wygląda podobnie
1 |
ObiektZAktualnąWartością.Should().MetodaPorównania(obiektDoPorównania) |
Assercje na obiektach
Z operacji na obiektach poza prostymi porównaniami typów prostych, każdy typ prosty ma specyficzne dla siebie porównania. Na przykład dla wartości całkowitych możemy sprawdzić z automatu czy liczba ma określoną wartość, czy może jest w jakimś zakresie
1 2 3 4 |
int actualInt = 234; actualInt.Should().NotBeInRange(0, 255); actualInt.Should().BePositive(); actualInt.Should().Be(234); |
lub dla wartości zmiennoprzecinkowych możemy określić wartość w przybliżeniu
1 2 |
double actualDouble = 234.567; actualDouble.Should().BeApproximately(234.5, 0.25); |
Niby proste zabiegi, ale zwiększają one czytelność porównań, przez co redukują możliwość powstania błędu.
Dla typów złożonych też istnieje możliwość porównania właściwości klas, wszystkich właściwości, co przy zmianach niweluje możliwość pominięcia, którejś z właściwości. W kodzie porównywania złożonych obiektów, które nie mają przeciążonego operatora równości ciągle za dużo widzę porównywania każdej właściwości w osobnym assercie. Dzięki FluentAssertions takie porównanie może wyglądać tak
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
ChopData actualComplex = new ChopData(); actualComplex.Words = new string[] { "ala", "ma", "kota" }; actualComplex.WordsCount = 3; ChopData expectedComplex = new ChopData(); expectedComplex.Words = new string[] { "ala", "ma", "kota" }; expectedComplex.WordsCount = 3; actualComplex.Should().BeEquivalentTo(expectedComplex); gdzie public class ChopData { public string[] Words { get; set; } public int WordsCount { get; set; } } |
Assercje na listach
Wśród operacji na listach możemy wybrać kilka dosyć ciekawych.
1 2 3 4 5 |
List<string> actualList = new List<string>() { "ala", "ma", "kota"}; actualList.Should().NotBeEmpty(); actualList.Should().NotContainNulls(); actualList.Should().OnlyHaveUniqueItems(); actualList.Should().HaveElementPreceding("kota", "ma"); |
Assercje a wyjątki
Testowanie wyjątków wygląda nieco inaczej niż w standardowym assercie, gdzie wykorzystujemy atrybuty. Tutaj wykorzystujemy akcję jako element, na którym operujemy. Sprawdzenie czy wyjątek zostanie wywołany może wyglądać tak :
1 2 3 |
LogicClass testedClass = new LogicClass(); Action act = () => testedClass.ThrowException() ; act.Should().Throw<Exception>().WithMessage("Invalida argument exception"); |
Biblioteka FluentAssertions jest bardzo dobrze udokumentowana. Ja polecam ze swojej strony odrobinę się nią pobawić. Metody są naprawdę bardzo intuicyjne i tak naprawdę wystarczy wykorzystać możliwości jakie daje nam intelisence. Gdyby ktoś jednak chciał poczytać więcej proponuję rozpocząć lekturę od strony projektu http://fluentassertions.com/
Proste zabawy dostępne są na moim GitHubie w katalogu https://github.com/Matejkos/BlogProjects/tree/master/FluentAssertionsPlayGround