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.

Wstęp

Aby stworzyć atrapę w NSubstitute, należy skorzystać z metody For klasy Substitute:

ICustomer customer = Substitute.For<ICustomer>();

Przekazanie parametrów do konstruktora odbywa się przez ww. metodę For. W niej definiujemy wszystkie argumenty konstruktora:

var customerValidator = Substitute.For<ICustomerValidator>();
var customerRepository = Substitute.For<CustomerRepository>(customerValidator);

Zamienniki w NSubstitute tworzone są w trybie “loose”. Dla przykładu:

ICustomer customer = Substitute.For<ICustomer>();
string firstName = customer.FirstName; // firstName = ""

Definicja zachowania

Zachowanie zamiennika można zdefiniować za pomocą metody rozszerzającej Returns:

ICustomer customer = Substitute.For<ICustomer>();
customer.GetAge().Returns(20);

Właściwości możemy definiować tak jak powyżej lub bezpośrednio przez dostęp do settera:

ICustomer customer = Substitute.For<ICustomer>();
customer.FirstName = "John";
customer.FirstName.Returns("John"); // ekwiwalentne do powyższego

Aby wyrzucić wyjątek, korzystamy z metody Throws:

ICustomer customer = Substitute.For<ICustomer>();
customer.GetAge().Throws<NotSupportedException>();

“Callback” możemy wykonać poprzez metodę AndDoes:

int a = 0;
ICustomer customer = Substitute.For<ICustomer>();

customer.GetAge()
        .Returns(20)         
        .AndDoes(info => a++);

// a = 0
customer.GetAge();
// a = 1

Parametr metody AndDoes jest typu Action<CallInfo>, dzięki czemu mamy dostęp, dzięki klasie CallInfo, do argumentów przekazanych metodzie.

Weryfikacja wywołań

Do zweryfikowania wywołania zamienników wykorzystuje się metodę Received oraz DidNotReceive:

var customerValidator = Substitute.For<ICustomerValidator>();
var customerRepository = new CustomerRepository(customerValidator);

var customer = Substitute.For<ICustomer>();
customer.FirstName = "John";

customerRepository.Add(customer);

customerValidator.Received().Validate(customer);

Received przyjmuje opcjonalnie jako parametr ilość oczekiwanych wywołań.

Argument Matching

“Argument matchery” działają w podobny sposób co w Moq i FakeItEasy.

Parametry metody możemy przekazać bezpośrednio:

calculator.Add(1, 2).Returns(3);

Lub, w przypadku złożonego dopasowania argumentów, za pomocą klasy Arg i metody Any oraz Is:

calculator.Add(Arg.Any<int>(), Arg.Is<int>(i => i > 0)).Returns(1);

Podsumowanie

Sposób obsługi naszych atrap jest o wiele prostszy i czytelniejszy w stosunku do Moq i FakeItEasy. Semantyka jest do bólu prosta i nie pozostawia zbyt wielu domysłów czytelnikowi. Wykorzystanie lambd zostało zminimalizowane, przez co kod jest też łatwiejszy do zrozumienia dla początkujących programistów zaczynających przygodę z C# i TDD.

Do tej pory poznaliśmy trzy biblioteki do tworzenia atrap – Moq, FakeItEasy oraz NSubstitute. Wszystkie mają otwarty kod źródłowy i są darmowe. Warto poeksperymentować z nimi, aby wyrobić sobie opinię na temat każdej z nich. Ja osobiście nie mam faworyta w tej kwestii, uznałbym że wszystkie trzy zajmują ex aequo pierwsze miejsce. Różnica jest nieznaczna, gdyż wszystkie trzy oparte są na wzorcu proxy (na jednym z ich wariancie) i bibliotece Castle.Core. Jest jeszcze kilka innych konkurentów na rynku, w tym płatnych i bardziej zaawansowanych. Nie będę ich jednak opisywać w tak szczegółowy sposób jak wyżej wymienione; niemniej jednak, temat powróci przy okazji omówienia typów bibliotek do tworzenia atrap i zaglądnięcia nieco pod maskę.

Linki zewnętrzne

2 thoughts on “Kurs TDD cz. 18: NSubstitute

  1. Pingback: dotnetomaniak.pl
  2. Pingback: Kurs TDD cz. 20: Mockowanie DateTime.Now, random, static, itp. | DariuszWoźniak .NET

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s