Projektowanie, Programowanie, Codzienność – BeniaminZaborski.com

6 Sierpień 2009

Ugryźć Spring.NET – (cz.7) Testy jednostkowe

Filed under: Ugryźć Spring.Net — Tags: , , , , — Beniamin Zaborski @ 21:50

W dzisiejszych czasach nikt już sobie nie wyobraża dobrze zaprojektowanej aplikacji biznesowej bez testów jednostkowych. Istnieją metodologie, które wręcz testy jednostkowe stawiają na pierwszym miejscu. Spring.NET idzie z duchem czasu i posiada wsparcie dla testów jednostkowych przy użyciu NUnit. Bądź co bądź to nadal najpopularniejszy framework testowy dla .NET, ale w zapowiedziach jest już wsparcie Spring.NET dla MbUnit i testów z Visual Studio.
Każdy kto się zetknął z testami jednostkowymi niejednokrotnie narzekał na to, iż spory nakład pracy trzeba włożyć aby przygotować środowisko uruchomieniowe. Mam tu na myśli utworzenie odpowiednich instancji serwisów, wstrzykiwanie do nich zależności obiektów DAO, itp. Często (znam to z autopsji) z tego powodu rezygnowało się z testów szczególnie w mniejszych projektach.
Wyobraźmy sobie najprostszy i najbardziej typowy scenariusz testów – testy serwisów warstwy biznesowej. Na pewno będziemy musieli zacząć od powołania instancji serwisów, a w następnej kolejności pomyśleć o zarządzaniu transakcjami, a także o tym czy wszystko wewnątrz serwisów zostało odpowiednio zainicjowane, tj. np. obiekty DAO.
Na szczęście o tych zmartwieniach pozwala nam zapomnieć mechanizm integracji z testami NUnit w Spring.NET.
Wygląda to dosyć prosto. Na początek informacja, że Spring.NET dostarcza nam klasy o nazwie AbstractDependencyInjectionSpringContextTests. Wystarczy, aby nasza klasa z testami dziedziczyła z tej klasy bazowej i przeciążyła właściwość ConfigLocations typu string[]. Jak można się domyślić ta właściwość zawiera wskazanie na pliki konfiguracyjne Spring.NET. Wygląda świetnie – przecież nikt nie będzie pisał plików dla kontenera IoC ponownie. Wykorzystajmy te z naszej aplikacji wskazując na nie.
Spójrzmy na prosty przykład:


[TestFixture]
public class AbonenciServiceTest : AbstractDependencyInjectionSpringContextTests
{
  private AbonenciService abonenciService;
  public AbonenciService AbonenciService
  {
    set { abonenciService = value; }
  }
  protected override string[] ConfigLocations
  {
    get { return new String[] { „assembly://BeezDev.Turrow.Model.Test/BeezDev.Turrow.Model.Test/Services.xml” }; }
  }

  [Test]
  public void PobierzListeAbonentow()
  {
    IList<AbonentDTO> listaAbonentow = this.abonenciService.PobierzListeAbonentow();
    Assert.AreEqual(0, listaAbonentow.Count);
    AbonentDTO abonentDTO = new AbonentDTO();
    abonentDTO.Id = Guid.NewGuid();
    abonentDTO.Imie = „Jan”;
    abonentDTO.Nazwisko = „Kowalski”;
    this.abonenciService.DodajAbonenta(abonentDTO);
    listaAbonentow = this.abonenciService.PobierzListeAbonentow();
    Assert.AreEqual(1, listaAbonentow.Count);
  }
}

Co tu widać? Dziedziczymy po wspomnianej klasie i uzupełniamy właściwość ConfigLocations wskazując nasz plik konfiguracyjny. W tym wypadku jest to tylko część konfiguracji dotycząca samych serwisów. Dzięki temu Spring.NET korzystając z konfiguracji zapisanej w Services.xml wstrzyknie nam instancję klasy AbonenciService odpowiednio ją inicjując.
Tak wygląda plik Services.xml:


<?xml version=”1.0″ encoding=”utf-8″ ?>
<objects xmlns=”http://www.springframework.net”&gt;
  <object id=”abonenciService” type=”BeezDev.Turrow.Wspolne.Model.AbonenciService, BeezDev.Turrow.Wspolne.Model”>
    <property name=”AbonentDAO” ref=”abonentDAO”/>
  </object>

  <object id=”abonentDAO” type=”BeezDev.Turrow.Wspolne.DataAccess.AbonentDAO, BeezDev.Turrow.Wspolne.DataAccess”/>

</objects>

Widzimy, że do serwisu dodatkowo została wstrzyknięta instancja klasy AbonentDAO.

W zdecydowanej większości systemów biznesowych dane są zapisywane w jakimś repozytorium, którym najczęściej jest baza danych. Istotną kwestią jest to, że takie dane dodane czy zmodyfikowane podczas testu nie powinny mieć wpływu na całość systemu. Oznacza to tyle, że test powinien się wykonywać w transakcji i wszelkie modyfikacje danych nie powinny być widoczne poza tą transakcją. Takie właśnie zachowanie daje nam Spring.NET, tj. w ramach testu tworzy transakcję, a następnie ją wycofuje. Odpowiedzialna za to jest jedna z klas bazowych AbstractTransactionalDbProviderSpringContextTests. Klasa ta bazuje na IPlatformTransactionManager, który jest dostarczony w ramach konfiguracji aplikacji. W pewnych przypadkach takie domyślne zachowanie nie jest wskazane, dlatego też mamy możliwość dziedziczenia po tej klasie i wprowadzenia własnych modyfikacji. Może nas np. w szczególnych przypadkach interesować zatwierdzenie transakcji zamiast domyślnego jej wycofania. Można to osiągnąć poprzez wywołanie metody SetComplete(). Podobnie możemy chcieć wycofać transakcję przed zakończeniem testu – wywołując EndTransaction();

Spring.NET dostarcza nam prosty, ale jakże pomocny mechanizm wsparcia dla testów jednostkowych NUnit. Pozwala nam to zaoszczędzić wiele cennego czasu przy budowaniu testów naszej aplikacji.

Dodaj komentarz »

Brak komentarzy.

RSS feed for comments on this post. TrackBack URI

Skomentuj

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

Logo WordPress.com

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

Zdjęcie z Twittera

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

Facebook photo

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

Google+ photo

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

Connecting to %s

Blog na WordPress.com.

%d bloggers like this: