Rhino Mocks vs moq vs NSubstitute

Po prawie rocznym okresie przerwy od pisania – potrzebowałem tego jak ryba wody, w międzyczasie udało mi się stworzyć kilka wideo tutoriali dla wydawnictwa Edugrafia i popracować nad kilkoma zewnętrznymi projektami (polecam) – wracam z tematem bardzo ważnym dla każdego programisty, czyli mocków.

Wydaje mi się, że powinniśmy od razu wyrzucić z grona bibliotek Rhino Mocks.

Dlaczego?

  • przestarzała biblioteka praktycznie bez aktualizacji
  • cholernie niewygodna składnia
  • przygotowanie kompletnych mocków zajmuje bardzo dużo czasu

Przykład:

Rhino Mocks:

var mockRepo = new MockRepository();
_articleManager = mockRepo.StrictMock<IArticleManager>();

moq:

_articleManager = new Mock<IArticleManager>();

NSubstitute:

_articleManager = Substitute.For<IArticleManager>();

Jak widać na załączonym kodzie, w przypadku RhinoMocks, utworzenie mocka dla managera wymaga 2 linii kodu, czyli stworzenia odpowiedniego repo dla mocków i rejestracji w nim naszego managera. Bez względu na to czy wersja Rhino Mocks wspiera AAA (wersja < 3.5), czy nie. W wersji 3.5 przynajmniej nie musimy korzystać z _articleManager.Replay();, bez której mockowanie np. metod w naszym managerze byłoby niemożliwe – do kodu należałoby ją wtedy dodać, co zwiększyłoby liczbę naszych linii do 3.

Idąc dalej – mockowanie metod, czyli mówimy o tym, co dla danej metody o określonym wejściu, chcielibyśmy zwrócić dla testu na wyjściu. Ta sama metoda dla:

Rhino Mocks:

_articleManager.Expect(a => a.GetArticlesByNumbers(kolekcja numerów)).Return(kolekcja artykułów).Repeat.Any();

moq:

 _articleManager.Setup(m => m.GetArticlesByNumbers(kolekcja numerów)).Returns(kolekcja artykułów);

NSubstitute:

 _articleManager.GetArticlesByNumbers(kolekcja numerów).Returns(kolekcja artykułów);

Powyższy kod służy mockowaniu danej metody tak, aby po przyjęciu jako parametr konkretnej kolekcji numerów, zwracała konkretną kolekcję artykułów. Dla Rhino Mocks składnia wygląda w następujący sposób: mamy nasz obiekt _articleManager, na którym oczekujemy (Expect), że nasza konkretna metoda (wyrażona przy użyciu lambda) zwróci nam konkretną kolekcję artykułów niezależnie od liczby jej wywołań. Oznacza to, że w przypadku, gdy w naszej metodzie testowej wywołamy tę metodę np. 3 razy, to za każdym razem zadziała. Jeżeli zapiszemy ją jako:

_articleManager.Expect(a => a.GetArticlesByNumbers(kolekcja numerów)).Return(kolekcja artykułów);

To wywoła się tylko za pierwszym razem, a za drugim rzuci wyjątkiem.

Zarówno w moq, jak i NSubstitute omijamy ten problem. W obydwu przypadkach wystarczy nam słówko Returns i to wszystko. Metodę będzie można wywołać 1, 5, czy 100 razy bez wyrzucania paskudnych wyjątków. Jednak dla moq składnia też jest brzydka. Na obiekcie _articleManager wywołujemy bezpośrednio .Setup, a następnie znowu (tak jak w Rhino Mocks) przy pomocy lambda określamy, że dla danej metody chcemy uzyskać określony output.

Inaczej ma się sprawa dla NSubstitute. Tutaj w elegancki sposób, metodę wywołujemy tak jak byśmy to zrobili w normalnym kodzie, bezpośrednio na _articleManager. Na końcu zaznaczamy tylko, że chcielibyśmy na wyjściu otrzymać konkretną kolekcję artykułów za pomocą słowa Returns. Wg mnie jest to bardzo czytelne, a przede wszystkim naturalne, ponieważ nie musimy się zastanawiać, czy na obiekcie mamy wywołać Setup, Expect, czy jeszcze coś innego.

Podsumowując, jeżeli macie możliwość zmiany biblioteki dla mocków w istniejących lub wpływ na zastosowanie jej w nowych projektach – śmiało, nie zawiedziecie się! 🙂

2 uwagi do wpisu “Rhino Mocks vs moq vs NSubstitute

Zostaw komentarz

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj /  Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

w

Connecting to %s