Kurs TDD cz. 21: Rodzaje frameworków do tworzenia atrap

Rodzaje framerków do tworzenia atrap możemy podzielić na dwie kategorie:

  • constrained (z ang. ograniczony)
  • unconstrained (nieograniczony)

constrained

Do pierwszej kategorii zaliczamy wszystkie do tej pory poznane frameworki do tworzenia atrap – Moq, FakeItEasy, NSubstite – a także Rhino Mocks, NMock oraz EasyMock. Ich cechą charakterystyczną jest ograniczona możliwość tworzenia atrap.

Biblioteki te generują kod dziedziczący atrapy w czasie rzeczywistym, w oparciu o kod pośredni (IL). Najczęściej atrapy są tworzone w oparciu o wzorzec projektowy dynamicznego proxy, który wymaga tego aby kod umożliwiał dziedziczenie. Oznacza to, że aby stworzyć atrapę potrzebujemy interfejsu do naszej klasy lub metody wirtualnej. Jako, że kluczem do stworzenia atrapy jest dziedziczenie, nasza klasa/metoda nie może być statyczna, niepubliczna, sealed oraz musi posiadać publiczny konstruktor. Oznacza to też, że kod zawarty w konstruktorze oraz polach klasy jest wykonywany przy tworzeniu atrapy.

Czym jest dynamiczne proxy?
Dynamiczne proxy to klasa, która implementuje interfejs lub klasę w trakcie wykonywania programu (run-time).

Biblioteki te są zwykle darmowe, a obiekty proxy są zwykle tworzone przy użyciu biblioteki Castle.Windsor.

unconstrained

Frameworki o “nieograniczonych możliwościach” to Typemock Isolator, JustMock i Microsoft Fakes. Są one napisane w oparciu o Common Language Runtime (CLR) Profiler, który udostępnia API pozwalające na większą kontrolę nad wykonywanym kodem. Możemy zatem wstrzykiwać nasz kod przed kompilacją kodu pośredniego oraz mamy dostęp do eventów wywoływanych w trakcie wykonywania naszego kodu.

Większa kontrola nad generowanym kodem oznacza, że frameworki te pozwalają na tworzenie atrap dla kodu, który nie musi być dziedziczony, a więc klasy/metody statyczne, prywatne, biblioteki zewnętrzne, klasy systemowe (np. DateTime), itp.

Ze względu na stopień skomplikowania pisania kodu w oparciu o API Profilera, frameworki te (poza Microsoftowym) są dostępne odpłatnie.

Continue reading

Kurs TDD cz. 20: Mockowanie DateTime.Now, random, static, itp.

Jedną z największych trudności dla osoby zaczynającej przygodę z testami jednostkowymi są:

  • Metody i klasy statyczne.
  • Niederministyczne lub/i niepowtarzalne zależności.
    • Testy jednostkowe muszą być deterministyczne i powtarzalne.
    • Musimy przyjąć zatem strategię wstrzykiwania alternatywnej implementacji dla wywołań DateTime.Now, funkcji losującej, itp.

W tym artykule przedstawię jedną ze strategii tworzenia atrap dla tego typu zależności.

Continue reading

Kurs TDD cz. 19: Mock, stub, fake, spy, dummy

Nomenklatura w świecie TDD, a w szczególności ta dotycząca tworzenia atrap, jest źródłem wielu niejasności. Powodem takiego stanu jest fakt, że definicje różnią się w zależności od źródła, tj. książki,  lub frameworka.

W poprzednich częściach poznaliśmy trzy najbardziej popularne frameworki do tworzenia atrap dla .NET, dla których:

  • Nie ma podziału na rodzaje atrap.
  • Atrapa (pod różną nazwą–mock, fake, substitute), poza subtelnymi różnicami, ma tę samą definicję i służy do jednakowych celów.

podzial definicji_2

Sprawa komplikuje się gdy mamy do czynienia z literaturą (książki i blogi) dotyczącą testów jednostkowych. Tutaj jest o tyle trudniej ponieważ:

  • Istnieje podział atrap ze względu na cel i zachowanie. Najbardziej popularnym podziałem jest (w moim subiektywnym odczuciu) podział wprowadzony przez Gerarda Meszarosa w książce xUnit Test Patterns na mock, stub, fake, test spy, dummy:

podzial definicji

  • Definicje atrap są różne, a niekiedy nawet wykluczające się:

Terminology Cross-Reference

W tym artykule przedstawię atrapy z xUnit Test Patterns napisane w Moq.

Continue reading

Kurs TDD cz. 18: NSubstitute

Pora przyjrzeć się trzeciemu najpopularniejszemu darmowemu frameworkowi, obok Moq i FakeItEasy, do tworzenia atrap w .NET – NSubstitute.

NSubstitute

Co wyróżnia tę bibliotekę:

  • Główny nacisk położono na prostotę w semantyce. Składnia biblioteki ma w założeniu jak najbardziej przypominać naturalny język. Ilość wyrażeń lambda została zredukowana do minimum.
  • W Moq każda atrapa to mock, w FakeItEasy fake, a w NSubstitute… substitute (z ang. “zamiennik”). Podobnie jak w dwóch wymienionych frameworkach, nie ma rozróżnienia na mock, stub, fake, spy, itp.

Dzięki temu, że biblioteka jest lekka, łatwa i przyjemna, doskonale nadaje się do celów edukacyjnych w temacie TDD i tworzenia atrap.

Continue reading

Kurs TDD cz. 17: FakeItEasy

Dziś w kursie TDD przyjrzymy się frameworkowi do tworzenia atrap, konkurencyjnemu do wcześniej poznanego Moq. FakeItEasy, bo o nim mowa, jest darmowy, łatwy w nauce, ma wsparcie dla C# i VB.NET, różni się od innych bibliotek nie tylko semantyką, ale także nieco innym podejściem do tematu tworzenia atrap.

fakeiteasy

Co więcej można powiedzieć o FakeItEasy?

  • W FakeItEasy wszystkie atrapy są fake’m. Nie ma rozróżnienia na mocki, stuby, itp.
  • Korzysta z API opartego na semantyce fluent i wyrażeniach lambda.
  • Jest rozszerzalny.
  • Posiada wsparcie dla bardziej zaawansowanych technik, m.in. strict fakes, argument matching, atrapy asynchronicznych metod.

Continue reading

Kurs TDD cz. 16: Moq cz. 2 – Argument Matching, Verify, Callback

W tym artykule przyjrzymy się ciut bardziej zaawansowanym technikom tworzenia atrap przy pomocy Moq:

  • argument matching,
  • verify,
  • callback.

Wszystkie przykłady zostaną zaprezentowane przy użyciu Moq, jednak konkurencyjne frameworki niewiele się różnią w tym zakresie.

Aby zobrazować przykład wykorzystania “argument matcherów”, weryfikacji i “callbacków” stwórzmy klasę CustomerRepository, która posiada metodę Add przyjmującą obiekt klasy implementującej interfejs ICustomer (lub w skrócie: klient). Jeśli walidacja przejdzie poprawnie, to klient zostanie dodany do kolekcji AllCustomers w klasie repozytorium. Interfejs repozytorium wygląda następująco:

public interface ICustomerRepository
{
    IReadOnlyList<ICustomer> AllCustomers { get; }
    bool Add(ICustomer customer);
}

Konstruktor klasy implementującej interfejs ICustomerRepository pozwala na wstrzyknięcie walidatora interfejsu ICustomerValidator:

public CustomerRepository(ICustomerValidator customerValidator)

Pełny kod repozytorium jest podany na końcu wpisu. Zachęcam jednak do tworzenia logiki biznesowej wraz z testami przy użyciu TDD i podanych scenariuszy, które pojawiają się sukcesywnie w tym wpisie.

Continue reading

Kurs TDD cz. 14: Testowanie zależności – atrapy obiektów

W części czternastej kursu Test-Driven Development omówimy technikę testowania zależności za pomocą atrap (jęz. ang. “mock”).

Test jednostkowy z definicji testuje zachowanie w izolacji, a więc bez zależności zewnętrznych. Takimi zależnościami są najczęściej inne klasy lub interfejsy, które posiadają zachowanie.

Testy jednostkowe powinny być wykonane w izolacji, gdyż zewnętrzne zależności mogą być:

– czasochłonne,
– niezaimplementowane lub nieukończone (np. interfejs, klasa abstrakcyjna, zalążek metody, pusta metoda),
– niedeterministyczne lub niepowtarzalne (np. aktualny czas),
– związane z dużą ilością innych klas (high class coupling),
– związane ze stanami, które są trudne do powtórzenia.

Continue reading

“Płynne asercje”, czyli jak ułatwić sobie życie korzystając z Fluent Assertions?

Wzorzec projektowy “fluent interface” (polski odpowiednik… płynny interfejs…?) przyjął się w środowisku .NETowym bardzo dobrze. I słusznie! “Płynna syntaktyka” znacznie poprawia czytelność pisanego kodu.

Jednym z sztandarowych przykładów jej użycia są asercje w testach. Pytanie który z poniższych zapisów jest bardziej naturalny?

Zwykły proszek, ekhm asercja:

Assert.AreEqual("Jan", firstName);

czy odpowiednik “fluent”:

firstName.ShouldBe("Jan");

Wybór pozostawiam Tobie, czytelnikowi, gdyż każdy ma swój gust. Niemniej jednak warto zaznajomić wiedzę na temat płynnych asercji.

Continue reading

Automatyczne generowanie testów jednostkowych: IntelliTest

IntelliTest to wewnętrzna funkcjonalność Visual Studio (Enterprise 2015), która służy do generowania tabeli danych wejściowych oraz zestawu testów jednostkowych. Dla danej metody generowane są dane wejściowe, w oparciu których mogą zostać wygenerowane testy jednostkowe.

Przypadki testowe tworzone są w oparciu o analizę każdego skoku warunkowego (conditional branch). Co więcej, tabela przypadków testowych zawiera scenariusze, które nie zostały obsłużone w naszej logice biznesowej, a które zwracają wyjątek (np. NullReferenceException lub dzielenie przez zero).

IntelliTest współpracuje natywnie z MSTest oraz poprzez rozszerzenia z xUnit.net i NUnit.

7167.2015_2D00_09_2D00_30_2D00_IntelliTest1_5F00_5C49D3D5

Continue reading