fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
3 minut

Konfiguracja zachowania metod dla stubów


07.08.2009

Po poprzednim odcinku potrafimy już dowolnie weryfikować i konfigurować wartości parametrów dla metod. Dzisiaj z kolei poustawiamy akcje, które mają się w momencie wywołania metod wykonać. Jest to czynność zdecydowanie prostsza, ponieważ właściwie wszystko mamy w Intellisense. Zobaczmy:

Zwracana wartość

Najprostsza możliwa konfiguracja to ustawienie wartości zwracanej przez metodę. Obiekt implementujący interfejs IMethodOptions<T> zwracany przez Stub(…) posiada konstrukcję Return(…) przyjmującą wartość, która zostanie zwrócona przez konfigurowaną akcję. W poniższy sposób zasymulujemy udane uwierzytelnienie dla podanego loginu i hasła:

  1:  authenticationService.Stub(x => x.Authenticate(userName, password)).Return(true);

Wyjątek

Inny banalny scenariusz to rzucenie wyjątku przez metodę. W ten sposób możemy zbadać zachowanie naszego kontrolera w sytuacji, w której usługa uwierzytelniająca bardzo dosadnie powie “coś jest nie tak!”:

  1:  authenticationService.Stub(x => x.Authenticate(userName, password))
  2:  	.Throw(new AuthenticationException());

Liczba powtórzeń

Pouczającym i bardziej skomplikowanym niż inne obszary przykładem wzorca Fluent Interface jest możliwość definiowania zachowania akcji daną liczbę razy. Poniższy kod zwróci true dla dwóch pierwszych wywołań, a w razie braku dalszej konfiguracji, wszystkie kolejne wywołania metody Authenticate będą zwracały wartość domyślną, czyli false:

  1:  authenticationService.Stub(x => x.Authenticate(userName, password))
  2:  	.Repeat.Twice()
  3:  	.Return(true);

Taka konstrukcja mówi, że metoda nie powinna zostać wywołana ani razu (choć nigdy nie zdarzyło mi się z tego korzystać) – wywołanie skończy się wyjątkiem na poziomie RhinoMocks, co spowoduje oblanie testu:

  1:  authenticationService.Stub(x => x.Authenticate(userName, password))
  2:  	.Repeat.Never();

Zaawansowane operacje

W przypadku bardziej zaawansowanych scenariuszy możemy natknąć się na konieczność odroczenia zdefiniowania zwracanej wartości do momentu, gdy znane będą parametry wywołania. Składania w RhinoMocks nie wygląda w tym przypadku ślicznie, ale da się coś takiego osiągnąć. Przykładowo poniższy kod zasymuluje powodzenie uwierzytelnienia jeśli login i hasło są takie same:

  1:  authenticationService.Stub(x => x.Authenticate(null, null))
  2:  	.IgnoreArguments().Return(false)
  3:  	.WhenCalled(opts => opts.ReturnValue = opts.Arguments[0] == opts.Arguments[1]);

Zwróćmy uwagę na środkową linijkę. Najpierw określamy, że definiowana akcja ma wykonać się niezależnie od wartości przekazanych do metody (IgnoreArguments()), a następnie jawnie definiujemy (dowolną) wartość zwracaną przez metodę. Dopiero potem, na koniec, nadpisujemy ReturnValue w wyrażeniu lambda przekazanym do metody WhenCalled() wołanej podczas określania czynności do wykonania przez RhinoMocks – mamy już wtedy dostęp do wartości parametrów.

Poniższy przykład również korzysta z tego mechanizmu.  Chcemy, aby każdorazowe pobranie użytkownika ze stuba implementującego interfejs IUsersRepository zwróciło nową instancję klasy User z odpowiednio ustawionym Id:

  1:  usersRepository.Stub(x => x.GetUser(0)).IgnoreArguments()
  2:  	.IgnoreArguments().Return(null)
  3:  	.WhenCalled(opts => opts.ReturnValue = new User {Id = (int) opts.Arguments[0]});

Kolejny obszar RhinoMocks i testowania z mockami – odkryty:). Następnym razem zerkniemy na zdarzenia w kontekście testów jednostkowych.

Comments are closed.

Kurs Gita

Zaawansowany frontend

Szkolenie z Testów

Szkolenie z baz danych

Książka

Zobacz również