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.

Biblioteki

Przykłady bibliotek

constrained generują kod pośredni w trakcie wykonywania (run-time):

  • Moq
  • FakeItEasy
  • NSubstitute
  • Rhino Mocks
  • NMock
  • EasyMock
  • JustMock Lite

unconstrained bazujące na API Profilera:

  • Typemock Isolator
  • JustMock
  • Microsoft Fakes (dawniej Moles)

No dobra, to który typ biblioteki wybrać?

Osobiście preferuję podejście przy użyciu “ograniczonych” frameworków, gdyż wymuszają one pisanie dobrego kodu w oparciu o programowanie zorientowane obiektowo. Podobnie jest z refaktoryzacją i poprawkami w nieprzetestowanym kodzie. Izolacja miejsca, które zmieniamy oraz tworzenie kodu który będzie w łatwy sposób testowalny również powoduje zwiększenie jakości kodu. Nie chcę przez to powiedzieć, że samo wykorzystanie bibliotek constrained gwarantuje nam poprawę kodu “gratis”. Dostajemy jednak informację zwrotną na temat designu naszych klas—nie możemy stworzyć atrapy jeśli nasza klasa nie jest testowalna z powodu np. statyczności lub braku interfejsu.

Użycie bibliotek unconstrained wiąże się z kilkoma pułapkami, m.in.

  • Możemy testować zbyt dużo nie wiedząc o tym. Niemal pełna dowolność powoduje, że możemy np. zacząć testować moduły prywatne, które z reguły nie powinny być testowane explicite.
  • Nie mamy informacji zwrotnej o jakości naszych klas względem programowania zorientowanego obiektowo.
  • Vendor lock-in. Uzależniamy się od dostawcy naszego frameworka. O ile można w prosty sposób zmigrować kod między Moq, FakeItEasy i NSubstitute, tak w przypadku tej klasy bibliotek może być o wiele trudniej. API frameworków unconstrained różnią się w bardziej znaczący sposób, przez co migracja kodu może być o wiele bardziej bolesna.

Frameworki constrained wymagają więcej wiedzy oraz doświadczenia na temat testowania oraz dobrego kodu, ale dzięki temu zyskujemy natychmiastową informację zwrotną na temat jakości naszego kodu. Ja stosuję z powodzeniem tę grupę bibliotek zarówno w przypadku greenfield (nowy kod), jak i brownfield (stary kod).

A wy jakie macie zdanie na temat tych dwóch grup frameworków?

Źródła

Opublikowano 11 kwietnia 2016

Blog o programowaniu
Dariusz Woźniak · GitHub · LinkedIn · Twitter · Goodreads