2010-10-22 15 views
8

Uświadom sobie to może brzmieć jak szerokie pytanie - więc pozwól mi wyjaśnić. Mam repozytorium odsłonięte przez interfejs, z dwoma konkretnymi implementacjami - MockRepository i EntityFrameworkRepository.Jak prawidłowo wykonać testy jednostkowe operacji CRUD w repozytorium?

Teraz mam projekt testu jednostkowego, dla którego wszystkie testy można uruchomić pod repozytorium albo, przeskakując przez linię w [TestInitialize].

Moje pytanie jest w zasadzie "Jak powinienem napisać testy".

Oto co mam:

C Reate

// Arrange. 
var foo = new Foo { .. }; 

// Act 
Repository.Add(foo); 
UnitOfWork.Commit(); 

// Assert 
Assert.IsTrue(foo.Id > 0); 

R etrieve

// Arrange. 
var fooToGet = 1; 

// Act 
var foo = Repository.FindSingle(fooToGet); 

// Assert 
Assert.IsNotNull(foo); 
Assert.AreEqual(foo.Id, fooToGet); 

U activeupdate

// Arrange. 
var fooToGet = 1; 
var nameToChangeFooTo = "FooBar"; 

// Act 
var foo = Repository.FindSingle(fooToGet); 
foo.Name = nameToChangeFooTo; 
UnitOfWork.Commit(); 
var fooRetrievedAgain = Repository.FindSingle(fooToGet); 

// Assert 
Assert.IsNotNull(foo); 
Assert.AreEqual(fooRetrievedAgain.Id, fooToGet); 
Assert.AreEqual(fooRetrievedAgain.Name, nameToChangeFooTo); 

D suĹ

// Arrange. 
var fooToGet = 1; 

// Act 
var foo = Repository.FindSingle(fooToGet); 
Repository.Remove(foo); 
UnitOfWork.Commit(); 
var fooRetrievedAgain = Repository.FindSingle(fooToGet); 

// Assert 
Assert.IsNull(fooRetrievedAgain); 

To działa ok, zarówno dla Mock i EF repozytorium, ale moim głównym problemem jest to C (Create). Nie wiem, jak przetestować operację dodawania w moim repozytorium. Nie czuje się dobrze co robię.

Przekazuje dla repozytorium EF, ale aby przekazać go w moim próbnym repozytorium musiałem użyć odbicia, aby zaktualizować identyfikator w zbiorze w pamięci (nieprzyjemnym).

Więc, czy możesz podzielić się radą na temat prawidłowych sposobów testowania operacji CRUD na schemacie repozytorium?

To aplikacja ASP.NET MVC, .NET 4, C#, Entity Framework 4 i Unit of Work/Repository Patterns.

Dzięki.

EDIT

prostu do wyjaśnienia facetów, nie są wszystko posiadaczami jednostek testy mam. Mam testy jednostkowe dla mojej warstwy usługi, a także testy reguł biznesowych.

Oba te elementy będą (i powinny) się nie powieść, jeśli powyższe testy repozytorium zawiodą. Na tym polega testowanie jednostkowe podstawowych operacji z moich repozytoriów. Czy się mylę?

+0

Co tu testujesz? Pachnie, jakbyś testował ze względu na pisanie testów. – jfar

+0

@jfar - faktycznie napisałem te testy zanim zaimplementowałem repozytoria (TDD). Mówisz, że nie przejmujesz się testowaniem swoich repozytoriów? Pomyśl o tym, jak wiele "bezsensownych" błędów można znaleźć w testowaniu biznesowym/systemowym. Ktoś może (i powinien) być podświetlony podczas testrun z kompilacją CI. Nie sądzisz? – RPM1984

+0

I pamiętaj, testuję przez 'interfejsy'. 'Repozytorium' jest typu' IRepository '. Więc wszystko, co próbuję zrobić, to upewnić się, że moje repozytoria są w stanie wykonywać podstawowe operacje na magazynie pamięci trwałej (czy to sklep to repozytorium symulowane w pamięci czy repozytorium EF). – RPM1984

Odpowiedz

3

Jedną z opcji jest użycie bazy danych wbudowanej w pamięć, takiej jak SqlLite, w celu przetestowania zachowania mapowań, zapytań i repozytoriów. Jest to omówione przez Ayende here, choć jego przykład używa NHibernate.

Inną opcją, która zdaje się odnosić do Państwa bezpośredniego zainteresowania ustawianiem identyfikatorów obiektów domeny, jest stosowanie podróbek testowych.Jest to omówione przez RhysC here.

+0

Pomyśl o swoim nieporozumieniu na moje pytanie. Mam już gotowe repozytorium Mock, pytam, jak mogę napisać testy, które powinny przejść zarówno w wersji próbnej, jak i repozytorium rzeczywistego. Spójrz na metodę testową Ayende. To jest informacja, którą chcę (jak poprawnie napisać test), a nie faktyczne szczegóły implementacji. – RPM1984

+1

Jeśli repozytorium nie zawiera skomplikowanej logiki i po prostu przekazuje żądania do bazowego sklepu.Wtedy bardziej odpowiedni może być test oparty na interakcji niż oparty na stanie. tj. wyśmiać sklep, który został wprowadzony do repozytorium. I twierdzą, że zostały na nią określone pewne metody. Zamiast potwierdzać wartość identyfikatora obiektu domeny. – martinl

+0

Zaakceptowana odpowiedź, gdy przechodzimy do SqlLite dla testowania w pamięci (nawet jeśli jest to integracja, sortowanie) – RPM1984

1

IMO, Twój utworzyć testowy powinien:

  • dodać jednostkę do repozytorium
  • assert został przydzielony identyfikator
  • odzyskać włożoną podmiot za pomocą identyfikatora
  • porównanie początkowej podmiotowi Odczytaj obiekt i upewnij się, że ich właściwości są takie same

Mam wiele testów jednostkowych, takich jak twój, główny d jest to, że używam głębokiej metody porównywania do porównywania instancji obiektów. Na przykład, moje testy U wyglądać następująco:

  • dodać jednostkę do repozytorium
  • odzyskać włożoną podmiot użyciu identyfikatora
  • zmianę niektórych właściwości podmiotu
  • zmiana podmiotu w repozytorium
  • pobrać zaktualizowaną podmiot za pomocą identyfikatora
  • porównanie zaktualizowaną podmiotu z podmiotem odczytu i upewnij się, że ich właściwości są takie same (można zdefiniować specyficzną logikę dla właściwości, które nie mogą być aktualizowane)
+0

Interesujące. Chociaż twój U (aktualizacja) również testuje dodawanie. Czy to naprawdę test jednostkowy? Reszta twojego testu U ma sens, ale nie należy go najpierw dodawać. IMO Test aktualizacji powinien obejmować pobranie istniejącego przedmiotu, a następnie jego aktualizację. Jednak twoja odpowiedź (i przemyślenia) są mile widziane. Dzięki. – RPM1984

+1

Widzę twój punkt, ale jeśli nie wstawiasz encji, musisz polegać na poprzednim stanie, który mógł zostać stworzony na przykład przez ClassInitialize. Naprawdę wolę, żeby moje testy były atomowe. Zauważ też, że nie testuję niczego na wstawionym elemencie. –

+0

Tak naprawdę to świetny punkt. Test powinien być atomowy. – RPM1984

Powiązane problemy