Archiwum kategorii: EntityFramework

Testy DB przy użyciu EntityFramework Core

Tak zgadza się, ten post będzie o testowiu warstwy dostępu do bazy danych. Pewnie zadajesz sobie pytanie po co testować bazę danych. Zgadzam się z tym w pełni w wielu przypadkach nie ma takiej potrzeby… Przecież można stworzyć interfejs, który w teście zamockuję i po sprawie…Tak to prawda w wielu przypadkach takie podejście będzie wystarczające ale co jeśli np. otrzymaliśmy w spadku system legacy i nie ma czasu na refactor całego rozwiązania, a chcemy napisać test integracyjny kontrolera MVC / WebAPI czy serwisu WCF.

Jeśli do tej pory używaliśmy EntityFramework czy jakiegoś innego Frameworka w naszej aplikacji to pewnym problemem podczas próby napisania testu był stan naszej aplikacji inaczej mówiąc dane jakie mamy w bazie danych. Pojawiało się pytanie czy podczas uruchamiania testów wykonywać je na specjalnym środowisku, utrzymywać specjalną bazę danych tylko pod testy, generować dane pod testy i na końcu sprzątać po sobie, może test uruchamiać w traksakcji… Wszystkie te czynności zajmowały dużo czasu….

I tu z pomocą przychodzi EntityFrameworkCore i InMemory provider dzięki, któremu możemy nasze testy uruchamiać niezależnie od bazy danych, a zarazem testować operacje CRUD na danych.

Jeśli używasz w swoich aplikacjach pełnego „starego” .NET, i nie masz możliwości użyć .NET Core nie kończ proszę czytać w tym miejscu. Ponieważ EF Core możesz uruchomić w normalnej aplikacji .NET i zaraz pokażę jak…

Na początek tworzę normalny projekt ASP.NET WebApi, jedyne wymaganie do wybranie docelowego frameworka minimum w wersji 4.6.1.

Dodajmy teraz paczkę Nuget dla EF Core, w tym celu instaluję paczkę Microsoft.EntityFrameworkCore.SqlServer ponieważ w projekcie WebAPI chcę użyć SQL Server.

Dzięki biblioteką .NET Standard możliwe jest pisanie aplikacji, które możemy uruchomić w dowolnym środowisku .NET, nie inaczej jest z EF Core!

Właściwie jeśli chodzi o podejście nic się nie zmieniło pomiędzy EF 6 a EF Core (EF Core to tak naprawdę EF 7), definiujemy klasę dla naszego kontekstu i używamy DbSet dla obsługi poszczególnych encji. Jedyna różnica to sposób w jaki konfiguruje się parametry połączenia, wcześniej przekazywało się connectionString poprzez kontruktor. Teraz przekazuje się DbContextOptions i korzysta się z DbContextOptionsBuilder do konfiguracji tego np. we frameworku Dependency Injection.

Użycie kontekstu w aplikacji praktycznie niczym się różni:

Przejdźmy teraz do testów. Aby umożliwić użycie EF Core i providera InMemory należy zainstalować paczkę  Microsoft.EntityFrameworkCore.InMemory.

Dzięki temu w naszym teście możemy skonfigurować DbContext tak aby wszystkie operacje były wykonywane w pamięci. Prosty test sprawdzający czy dane prawidłowo zostały zapisane w bazie danych wygląda następująco:

Celowo dodałem bloki using aby zobrazować potencjał jaki drzemie w tego typu podejściu. Moglibyśmy spreparować odpowiedni DbContext i uruchamiać na nim całą serię testów naszych CRUD-ów. Zawsze gdy tworzony jest nowy kontekst bazy danych EF korzysta wewnętrznie z cache i dane, które już zapisaliśmy są dostępne zupełnie jak byśmy korzystali z bazy danych!

Podsumowując myślę, że naprawdę warto się zastanowić nad wykorzystaniem tego Frameworka, koszt przejścia z wersji EF 6 do EF Core nawet jeśli korzystamy ze „starego” .NET nie powinien być duży. Dzięki temu możemy zaoszczędzić sporo czasu i już nie zastanawiać się jak zapewnić prawidłowe dane pod testy.