Dopiero zaczynam od testów jednostkowych i ogólnie TDD. Parałem się wcześniej, ale teraz jestem zdeterminowany, aby dodać to do mojego przepływu pracy i napisać lepsze oprogramowanie.
Zadałem wczoraj pytanie, które zawierało to, ale wydaje się, że jest to pytanie samo w sobie. Usiadłem, aby rozpocząć wdrażanie klasy usług, której użyję do oderwania logiki biznesowej od kontrolerów i odwzorowania na określone modele i interakcje z danymi za pomocą EF6.
Problem polega na tym, że już sam się zablokowałem, ponieważ nie chciałem wyodrębniać EF z repozytorium (będzie nadal dostępny poza usługami dla określonych zapytań itp.) I chciałbym przetestować moje usługi (zostanie użyty kontekst EF) .
Tutaj wydaje mi się, że jest pytanie, czy warto to robić? Jeśli tak, jak ludzie robią to na wolności w świetle nieszczelnych abstrakcji spowodowanych przez IQueryable i wielu świetnych postów Ladislava Mrnki na temat testów jednostkowych, które nie są proste z powodu różnic w dostawcach Linq podczas pracy z pamięcią implementacja dołączona do określonej bazy danych.
Kod, który chcę przetestować, wydaje się dość prosty. (to tylko fikcyjny kod, aby spróbować zrozumieć, co robię, chcę sterować tworzeniem za pomocą TDD)
Kontekst
public interface IContext
{
IDbSet<Product> Products { get; set; }
IDbSet<Category> Categories { get; set; }
int SaveChanges();
}
public class DataContext : DbContext, IContext
{
public IDbSet<Product> Products { get; set; }
public IDbSet<Category> Categories { get; set; }
public DataContext(string connectionString)
: base(connectionString)
{
}
}
Usługa
public class ProductService : IProductService
{
private IContext _context;
public ProductService(IContext dbContext)
{
_context = dbContext;
}
public IEnumerable<Product> GetAll()
{
var query = from p in _context.Products
select p;
return query;
}
}
Obecnie myślę o zrobieniu kilku rzeczy:
- Mockowanie kontekstu EF za pomocą czegoś podobnego do tego podejścia - Mockowanie EF podczas testowania jednostkowego lub bezpośrednio przy użyciu symulowanej struktury w interfejsie, takim jak moq - biorąc ból, który testy jednostkowe mogą przejść, ale niekoniecznie działają od końca do końca i wykonać kopię zapasową za pomocą testów integracji?
- Może używając czegoś takiego jak Effort, aby kpić z EF - nigdy go nie używałem i nie jestem pewien, czy ktoś inny używa go na wolności?
- Nie przejmujesz się testowaniem czegokolwiek, co po prostu wywołuje z powrotem do EF - więc zasadniczo metody usługi, które bezpośrednio wywołują EF (getAll itp.) Nie są testowane jednostkowo, ale tylko testowane pod kątem integracji?
Czy ktoś faktycznie robi to bez repozytorium i odnosi sukcesy?
Odpowiedzi:
To temat, który mnie bardzo interesuje. Jest wielu purystów, którzy twierdzą, że nie powinno się testować technologii takich jak EF czy NHibernate. Mają rację, są już bardzo rygorystycznie przetestowani i jak stwierdzono w poprzedniej odpowiedzi, często bezcelowe jest spędzanie ogromnej ilości czasu na testowaniu tego, czego nie masz.
Jednak jesteś właścicielem bazy danych pod spodem! W tym miejscu moim zdaniem załamuje się to podejście, nie trzeba sprawdzać, czy EF / NH poprawnie wykonują swoją pracę. Musisz sprawdzić, czy twoje mapowania / implementacje działają z twoją bazą danych. Moim zdaniem jest to jedna z najważniejszych części systemu, który możesz przetestować.
Ściśle mówiąc jednak wychodzimy z domeny testów jednostkowych na rzecz testów integracyjnych, ale zasady pozostają takie same.
Pierwszą rzeczą, którą musisz zrobić, jest możliwość mockowania swojego DAL, aby twój BLL mógł być testowany niezależnie od EF i SQL. To są twoje testy jednostkowe. Następnie musisz zaprojektować testy integracji, aby udowodnić swoje DAL, moim zdaniem są one równie ważne.
Należy wziąć pod uwagę kilka kwestii:
Istnieją dwa główne podejścia do konfigurowania bazy danych, pierwsze to uruchomienie skryptu UnitTest do tworzenia bazy danych. Zapewnia to, że baza danych testów jednostkowych będzie zawsze w tym samym stanie na początku każdego testu (możesz to zresetować lub uruchomić każdy test w transakcji, aby to zapewnić).
Inną opcją jest to, co robię, uruchamiam określone konfiguracje dla każdego indywidualnego testu. Uważam, że jest to najlepsze podejście z dwóch głównych powodów:
Niestety twoim kompromisem jest tutaj szybkość. Uruchomienie wszystkich tych testów wymaga czasu, aby uruchomić wszystkie te skrypty konfiguracyjne / niszczące.
I ostatnia uwaga: napisanie tak dużej ilości kodu SQL w celu przetestowania ORM może być bardzo ciężką pracą. W tym miejscu przyjmuję bardzo paskudne podejście (tutaj puryści się ze mną nie zgodzą). Używam mojego ORM do tworzenia testu! Zamiast mieć osobny skrypt dla każdego testu DAL w moim systemie, mam fazę konfiguracji testu, która tworzy obiekty, dołącza je do kontekstu i zapisuje. Następnie przeprowadzam test.
To dalekie od idealnego rozwiązania, jednak w praktyce wydaje mi się, że jest DUŻO łatwiejsze w zarządzaniu (zwłaszcza gdy masz kilka tysięcy testów), w przeciwnym razie tworzysz ogromną liczbę skryptów. Praktyczność ponad czystość.
Bez wątpienia spojrzę wstecz na tę odpowiedź za kilka lat (miesiące / dni) i nie zgodzę się ze sobą, ponieważ zmieniło się moje podejście - jednak takie jest moje obecne podejście.
Podsumowując wszystko, co powiedziałem powyżej, oto mój typowy test integracji DB:
Kluczową rzeczą, na którą należy zwrócić uwagę, jest to, że sesje dwóch pętli są całkowicie niezależne. W swojej implementacji RunTest musisz upewnić się, że kontekst jest zatwierdzony i zniszczony, a twoje dane mogą pochodzić z bazy danych tylko w drugiej części.
Edycja 13/10/2014
Powiedziałem, że prawdopodobnie poprawię ten model w ciągu najbliższych miesięcy. Chociaż w dużej mierze opowiadam się za podejściem, które zaleciłem powyżej, nieznacznie zaktualizowałem mój mechanizm testowania. Teraz mam tendencję do tworzenia jednostek w TestSetup i TestTearDown.
Następnie przetestuj każdą właściwość indywidualnie
Istnieje kilka powodów takiego podejścia:
Wydaje mi się, że dzięki temu klasa testów jest prostsza, a testy bardziej szczegółowe ( pojedyncze potwierdzenia są dobre )
Edycja 03.05.2015
Kolejna rewizja tego podejścia. Chociaż konfiguracje na poziomie klasy są bardzo przydatne w testach, takich jak ładowanie właściwości, są mniej przydatne, gdy wymagane są różne konfiguracje. W tym przypadku utworzenie nowej klasy dla każdego przypadku jest przesadą.
Aby w tym pomóc, mam teraz zwykle dwie klasy bazowe
SetupPerTest
iSingleSetup
. Te dwie klasy uwidaczniają platformę zgodnie z wymaganiami.W
SingleSetup
mamy bardzo podobny mechanizm, jak opisano w mojej pierwszej edycji. Przykładem może byćJednak odniesienia, które zapewniają, że ładowane są tylko prawidłowe elementy, mogą korzystać z podejścia SetupPerTest
Podsumowując, oba podejścia działają w zależności od tego, co próbujesz przetestować.
źródło
Informacje zwrotne na temat wysiłków tutaj
Po wielu lekcjach zacząłem używać Effort w moich testach: podczas testów Context jest budowany przez fabrykę, która zwraca wersję w pamięci, co pozwala mi za każdym razem testować na pustej planszy. Poza testami fabryka jest rozwiązywana do takiej, która zwraca cały kontekst.
Mam jednak wrażenie, że testowanie w pełni funkcjonalnej makiety bazy danych zwykle przeciąga testy w dół; zdajesz sobie sprawę, że musisz zadbać o skonfigurowanie całej masy zależności, aby przetestować jedną część systemu. Masz również tendencję do wspólnego organizowania testów, które mogą nie być powiązane, tylko dlatego, że istnieje tylko jeden ogromny obiekt, który obsługuje wszystko. Jeśli nie zwracasz uwagi, może się okazać, że zamiast testów jednostkowych wykonujesz testy integracyjne
Wolałbym przetestować coś bardziej abstrakcyjnego niż ogromny DBContext, ale nie mogłem znaleźć najlepszego miejsca między znaczącymi testami a testami gołymi kościami. Kredytuj to mojemu brakowi doświadczenia.
Dlatego uważam, że Wysiłek jest interesujący; jeśli chcesz zacząć działać, jest to dobre narzędzie do szybkiego rozpoczęcia pracy i uzyskania wyników. Uważam jednak, że następnym krokiem powinno być coś nieco bardziej eleganckiego i abstrakcyjnego i to właśnie zamierzam zbadać dalej. Dodawanie tego posta do ulubionych, aby zobaczyć, dokąd pójdzie dalej :)
Edytuj, aby dodać : rozgrzewka wymaga trochę czasu, więc patrzysz na ok. 5 sekund przy uruchomieniu testowym. Może to stanowić problem, jeśli chcesz, aby Twój zestaw testów był bardzo wydajny.
Edytowano dla wyjaśnienia:
Użyłem programu Effort do przetestowania aplikacji usług sieciowych. Każda wiadomość M, która wchodzi, jest kierowana do a
IHandlerOf<M>
przez Windsor. Castle.Windsor rozwiązuje problem,IHandlerOf<M>
który rozwiązuje zależności składnika. Jedną z tych zależności jestDataContextFactory
, która pozwala programowi obsługi zapytać o fabrykęW moich testach bezpośrednio tworzę instancję komponentu IHandlerOf, mockuję wszystkie komponenty podrzędne SUT i obsługuję
DataContextFactory
procedurę obsługi.Oznacza to, że nie wykonuję testów jednostkowych w ścisłym tego słowa znaczeniu, ponieważ moje testy trafiają w DB. Jednak, jak powiedziałem powyżej, pozwoliło mi to zacząć działać i szybko przetestować niektóre punkty w aplikacji
źródło
Jeśli chcesz przeprowadzić testy jednostkowe , musisz odizolować kod, który chcesz przetestować (w tym przypadku usługę), od zasobów zewnętrznych (np. Baz danych). Prawdopodobnie można to zrobić za pomocą jakiegoś dostawcy EF w pamięci , jednak znacznie bardziej powszechnym sposobem jest wyodrębnienie implementacji EF, np. Za pomocą pewnego rodzaju wzorca repozytorium. Bez tej izolacji wszelkie napisane przez Ciebie testy będą testami integracyjnymi, a nie jednostkowymi.
Jeśli chodzi o testowanie kodu EF - piszę zautomatyzowane testy integracji dla moich repozytoriów, które zapisują różne wiersze do bazy danych podczas ich inicjalizacji, a następnie wywołuję moje implementacje repozytoriów, aby upewnić się, że zachowują się zgodnie z oczekiwaniami (np. Upewniając się, że wyniki są poprawnie filtrowane lub że są posortowane we właściwej kolejności).
Są to testy integracji, a nie testy jednostkowe, ponieważ testy te polegają na posiadaniu połączenia z bazą danych oraz na tym, że docelowa baza danych ma już zainstalowany najnowszy, aktualny schemat.
źródło
Oto rzecz, Entity Framework jest implementacją, więc pomimo faktu, że abstrakcja złożoność interakcji z bazą danych, bezpośrednia interakcja jest nadal ścisłym sprzężeniem i dlatego testowanie jest mylące.
Testowanie jednostkowe polega na testowaniu logiki funkcji i każdego z jej potencjalnych wyników w oderwaniu od wszelkich zależności zewnętrznych, którymi w tym przypadku jest magazyn danych. Aby to zrobić, musisz mieć możliwość kontrolowania zachowania magazynu danych. Na przykład, jeśli chcesz zapewnić, że twoja funkcja zwraca fałsz, jeśli pobrany użytkownik nie spełnia jakiegoś zestawu kryteriów, wtedy twoja [udawana] składnica danych powinna być skonfigurowana tak, aby zawsze zwracała użytkownika, który nie spełnia kryteriów, i vice versa dla przeciwnego twierdzenia.
Powiedziawszy to i akceptując fakt, że EF jest implementacją, prawdopodobnie poparłbym pomysł abstrakcji repozytorium. Wydaje się trochę zbędne? Tak nie jest, ponieważ rozwiązujesz problem polegający na odizolowaniu kodu od implementacji danych.
W DDD repozytoria zawsze zwracają tylko zagregowane korzenie, a nie DAO. W ten sposób konsument repozytorium nigdy nie musi wiedzieć o implementacji danych (a nie powinien) i możemy to wykorzystać jako przykład rozwiązania tego problemu. W takim przypadku obiekt generowany przez EF jest DAO i jako taki powinien być ukryty w aplikacji. To kolejna zaleta repozytorium, które zdefiniujesz. Obiekt biznesowy można zdefiniować jako typ zwracany zamiast obiektu EF. Teraz repozytorium ukrywa wywołania EF i mapuje odpowiedź EF na ten obiekt biznesowy zdefiniowany w sygnaturze repozytorium. Teraz możesz użyć tego repozytorium zamiast zależności DbContext, którą wstrzykujesz do swoich klas, a co za tym idzie, możesz teraz mockować ten interfejs, aby uzyskać kontrolę potrzebną do przetestowania kodu w izolacji.
To trochę więcej pracy i wielu kciuka na nosie, ale to rozwiązuje prawdziwy problem. Istnieje dostawca pamięci, o którym wspomniano w innej odpowiedzi, która może być opcją (nie próbowałem tego), a samo jego istnienie jest dowodem na potrzebę takiej praktyki.
Zupełnie nie zgadzam się z najlepszą odpowiedzią, ponieważ omija ona prawdziwy problem, jakim jest izolacja kodu, a następnie przechodzi do testowania mapowania. Oczywiście przetestuj swoje mapowanie, jeśli chcesz, ale zajmij się tutaj rzeczywistym problemem i uzyskaj rzeczywiste pokrycie kodu.
źródło
Nie chciałbym testować kodu jednostkowego, którego nie posiadam. Co tu testujesz, że kompilator MSFT działa?
To powiedziawszy, aby ten kod był testowalny, prawie MUSISZ oddzielić warstwę dostępu do danych od kodu logiki biznesowej. To, co robię, to bierze wszystkie moje rzeczy EF i umieszczam je w (lub wielu) klasach DAO lub DAL, które również mają odpowiedni interfejs. Następnie piszę usługę, w której obiekt DAO lub DAL zostanie wstrzyknięty jako zależność (najlepiej iniekcja konstruktora), do której odwołuje się interfejs. Teraz część, która musi zostać przetestowana (kod), można łatwo przetestować, wyszydzając interfejs DAO i wstrzykując go do instancji usługi w ramach testu jednostkowego.
Uznałbym warstwy dostępu do danych na żywo za część testów integracyjnych, a nie testów jednostkowych. Widziałem facetów weryfikujących liczbę podróży do bazy danych w stanie hibernacji, ale pracowali nad projektem, który obejmował miliardy rekordów w ich magazynie danych, a te dodatkowe podróże naprawdę się liczyły.
źródło
Czasami grzebałem, aby dojść do tych rozważań:
1- Jeśli moja aplikacja ma dostęp do bazy danych, dlaczego test nie powinien? A jeśli coś jest nie tak z dostępem do danych? Testy muszą to wiedzieć wcześniej i ostrzec się o problemie.
2- Wzorzec repozytorium jest nieco trudny i czasochłonny.
Wymyśliłem więc takie podejście, które nie uważam za najlepsze, ale spełniło moje oczekiwania:
Aby to zrobić, konieczne jest:
1- Zainstaluj EntityFramework w projekcie testowym. 2- Umieść parametry połączenia w pliku app.config projektu testowego. 3- Odwołaj się do dll System.Transactions w projekcie testowym.
Unikalnym efektem ubocznym jest to, że ziarno tożsamości będzie rosło podczas próby wstawienia, nawet jeśli transakcja zostanie przerwana. Ale ponieważ testy są przeprowadzane na programistycznej bazie danych, nie powinno to stanowić problemu.
Przykładowy kod:
źródło
Krótko mówiąc, nie, sok nie jest wart wyciskania, aby przetestować metodę usługi za pomocą jednej linii, która pobiera dane modelu. Z mojego doświadczenia wynika, że ludzie, którzy dopiero zaczynają przygodę z TDD, chcą przetestować absolutnie wszystko. Stary kasztan abstrakcji fasady do frameworka strony trzeciej tylko po to, abyś mógł stworzyć makietę tego interfejsu API frameworka, za pomocą którego bastardujesz / rozszerzasz, aby można było wstrzykiwać fikcyjne dane, ma dla mnie niewielką wartość. Każdy ma inny pogląd na to, ile testów jednostkowych jest najlepsze. Obecnie jestem bardziej pragmatyczny i zadaję sobie pytanie, czy mój test naprawdę dodaje wartość do produktu końcowego i jakim kosztem.
źródło
Chcę podzielić się podejściem, które zostało skomentowane i krótko omówione, ale pokażę rzeczywisty przykład, którego obecnie używam, aby pomóc w testach jednostkowych usług opartych na EF.
Po pierwsze, chciałbym użyć dostawcy w pamięci z EF Core, ale chodzi o EF 6. Ponadto w przypadku innych systemów magazynowania, takich jak RavenDB, byłbym również zwolennikiem testowania za pośrednictwem dostawcy bazy danych w pamięci. Ponownie - ma to na celu pomóc w testowaniu kodu opartego na EF bez zbytniej ceremonii .
Oto cele, które wyznaczyłem sobie, wymyślając wzór:
Zgadzam się z poprzednimi stwierdzeniami, że EF nadal jest szczegółem implementacyjnym i można czuć, że trzeba go wyabstrahować, aby wykonać „czysty” test jednostkowy. Zgadzam się też, że idealnie chciałbym upewnić się, że sam kod EF działa - ale dotyczy to bazy danych piaskownicy, dostawcy w pamięci itp. Moje podejście rozwiązuje oba problemy - można bezpiecznie testować jednostkowo kod zależny od EF i tworzyć testy integracji w celu przetestowania kodu EF w szczególności.
Sposób, w jaki to osiągnąłem, polegał na prostym hermetyzowaniu kodu EF w dedykowanych klasach Query i Command. Pomysł jest prosty: po prostu zawiń dowolny kod EF w klasę i polegaj na interfejsie w klasach, które pierwotnie go używały. Głównym problemem, który musiałem rozwiązać, było uniknięcie dodawania wielu zależności do klas i konfigurowania dużej ilości kodu w moich testach.
Tutaj pojawia się użyteczna, prosta biblioteka: Mediatr . Pozwala na proste przesyłanie komunikatów w trakcie procesu i robi to poprzez oddzielenie „żądań” od programów obsługi, które implementują kod. Ma to dodatkową zaletę w postaci oddzielenia „co” od „jak”. Na przykład, hermetyzując kod EF na małe fragmenty, umożliwia zastąpienie implementacji innym dostawcą lub zupełnie innym mechanizmem, ponieważ wszystko, co robisz, to wysyłanie żądania wykonania akcji.
Wykorzystując iniekcję zależności (z frameworkiem lub bez niego - preferencje użytkownika), możemy łatwo mockować mediatora i kontrolować mechanizmy żądania / odpowiedzi, aby umożliwić testowanie jednostkowe kodu EF.
Po pierwsze, powiedzmy, że mamy usługę, która ma logikę biznesową, którą musimy przetestować:
Czy zaczynasz dostrzegać korzyści płynące z tego podejścia? Nie tylko jawnie hermetyzujesz cały kod związany z EF w klasach opisowych, ale także pozwalasz na rozszerzalność, usuwając problem implementacji dotyczący sposobu obsługi tego żądania - ta klasa nie obchodzi, czy odpowiednie obiekty pochodzą z EF, MongoDB, lub plik tekstowy.
Teraz dla wnioskodawcy i osoby obsługującej, za pośrednictwem MediatR:
Jak widać, abstrakcja jest prosta i zamknięta. Jest to także absolutnie sprawdzalne , ponieważ w teście integracyjnym, to mógłby przetestować tę klasę indywidualnie - nie ma obawy roboczych mieszane tutaj.
Jak więc wygląda test jednostkowy naszej usługi funkcji? To bardzo proste. W tym przypadku używam Moq do robienia kpiny (używaj tego, co cię uszczęśliwia):
Widzisz, że potrzebujemy tylko jednej konfiguracji i nie musimy nawet niczego konfigurować - to bardzo prosty test jednostkowy. Wyjaśnijmy: jest to całkowicie możliwe bez czegoś takiego jak Mediatr (po prostu zaimplementowałbyś interfejs i wyszywałbyś go np. Do testów
IGetRelevantDbObjectsQuery
), ale w praktyce dla dużej bazy kodu z wieloma funkcjami i zapytaniami / poleceniami, uwielbiam hermetyzację i wrodzone wsparcie DI oferuje Mediatr.Jeśli zastanawiasz się, jak organizuję te zajęcia, jest to całkiem proste:
Organizowanie według wycinków funkcji nie ma znaczenia, ale pozwala to zachować cały odpowiedni / zależny kod razem i łatwo go znaleźć. Co najważniejsze, oddzielam zapytania od poleceń - kierując się zasadą separacji poleceń / zapytań .
To spełnia wszystkie moje kryteria: jest to niska ceremonia, łatwa do zrozumienia i są dodatkowe ukryte korzyści. Na przykład, jak radzisz sobie z zapisywaniem zmian? Teraz możesz uprościć kontekst Db, używając interfejsu roli (
IUnitOfWork.SaveChangesAsync()
) i pozorowane wywołania interfejsu pojedynczej roli lub możesz hermetyzować zatwierdzanie / wycofywanie w ramach swoich RequestHandlers - jednak wolisz to robić, o ile jest to możliwe do utrzymania. Na przykład kusiło mnie, aby utworzyć jedno ogólne żądanie / procedurę obsługi, w którym po prostu przekazałbyś obiekt EF i zapisałby / zaktualizował / usunąłby go - ale musisz zapytać, jaki jest twój zamiar i pamiętaj, że jeśli chcesz zamienić moduł obsługi z innym dostawcą / implementacją pamięci masowej, prawdopodobnie powinieneś utworzyć jawne polecenia / zapytania, które reprezentują to, co zamierzasz zrobić. Najczęściej pojedyncza usługa lub funkcja będzie wymagać czegoś konkretnego - nie twórz ogólnych rzeczy, zanim będziesz ich potrzebować.Istnieją oczywiście zastrzeżenia do tego wzorca - możesz posunąć się za daleko, korzystając z prostego mechanizmu pub / sub. Ograniczyłem swoją implementację tylko do abstrakcyjnego kodu związanego z EF, ale żądni przygód programiści mogli zacząć używać MediatR, aby przesadzić i wysyłać wiadomości - coś, co dobre praktyki przeglądu kodu i recenzje powinny złapać. Jest to problem związany z procesem, a nie problemem z MediatR, więc po prostu bądź świadomy tego, jak używasz tego wzorca.
Potrzebowałeś konkretnego przykładu tego, jak ludzie testują jednostkowe / kpią z EF i jest to podejście, które z powodzeniem sprawdza się w naszym projekcie - a zespół jest bardzo zadowolony z tego, jak łatwo je zastosować. Mam nadzieję, że to pomoże! Podobnie jak w przypadku wszystkich rzeczy w programowaniu, istnieje wiele podejść i wszystko zależy od tego, co chcesz osiągnąć. Cenię prostotę, łatwość obsługi, łatwość konserwacji i wykrywalność - a to rozwiązanie spełnia wszystkie te wymagania.
źródło
Istnieje Effort, który jest dostawcą bazy danych struktury jednostki pamięci. Właściwie tego nie próbowałem ... Haa właśnie zauważyłem, że wspomniano o tym w pytaniu!
Alternatywnie możesz przełączyć się na EntityFrameworkCore, który ma wbudowanego dostawcę bazy danych w pamięci.
https://blog.goyello.com/2016/07/14/save-time-mocking-use-your-real-entity-framework-dbcontext-in-unit-tests/
https://github.com/tamasflamich/effort
Użyłem fabryki, aby uzyskać kontekst, więc mogę stworzyć kontekst zbliżony do jego użycia. Wydaje się, że działa to lokalnie w Visual Studio, ale nie na moim serwerze kompilacji TeamCity, jeszcze nie wiem, dlaczego.
źródło
Lubię oddzielać filtry od innych części kodu i testować je zgodnie z opisem na moim blogu tutaj http://coding.grax.com/2013/08/testing-custom-linq-filter-operators.html
Biorąc to pod uwagę, testowana logika filtru nie jest identyczna z logiką filtru wykonywaną podczas uruchamiania programu ze względu na tłumaczenie między wyrażeniem LINQ a bazowym językiem zapytań, takim jak T-SQL. Mimo to pozwala mi to zweryfikować logikę filtra. Nie martwię się zbytnio o występujące tłumaczenia i takie rzeczy, jak rozróżnianie wielkości liter i obsługa wartości zerowych, dopóki nie przetestuję integracji między warstwami.
źródło
Ważne jest, aby przetestować to, czego oczekujesz od struktury encji (tj. Zweryfikować swoje oczekiwania). Jednym ze sposobów, aby to zrobić, z powodzeniem, jest użycie moq, jak pokazano w tym przykładzie (zbyt długo, aby skopiować do tej odpowiedzi):
https://docs.microsoft.com/en-us/ef/ef6/fundamentals/testing/mocking
Jednak bądź ostrożny ... Nie gwarantuje się, że kontekst SQL zwróci rzeczy w określonej kolejności, chyba że masz w zapytaniu linq odpowiednie "OrderBy", więc możliwe jest zapisanie rzeczy, które przechodzą, gdy testujesz używając listy w pamięci ( linq-to-entity), ale kończy się niepowodzeniem w środowisku uat / live, gdy zostanie użyte (linq-to-sql).
źródło