Dlaczego w testowaniu jednostkowym miałbym dwa razy tworzyć repozytorium?

10

Innego dnia czytałem trochę o Testowaniu Jednostek i widziałem kilka przykładów, w których ludzie tworzą interfejs repozytorium (tj. IExampleRepository), A następnie tworzą prawdziwe repozytorium ( public class ExampleRepository : IExampleRepository) i repozytorium, które będzie używane do testowania jednostek ( FakeExampleRepository : IExampleRepository).

W IExampleRepositoryimplementacji stosowano te same metody, co w ExampleRepositoryprzypadku różnych zapytań Linq.

Jaki jest tutaj dokładnie cel? Myślałem, że jedna część jednostki testującej twój kod upewnia się, że metoda działa poprawnie? Ale kiedy używam dwóch całkowicie różnych zapytań, jednego dla „rzeczywistego” i jednego w teście, jaki sens ma test?

jao
źródło

Odpowiedzi:

8

Jednym z celów testów jednostkowych jest testowanie tylko jednej rzeczy na raz, tj. Pojedynczej klasy i metody. Jeśli samo repozytorium nie jest testowane, zwykle wyśmiewasz to w jakiś sposób, aby po prostu przetestować logikę w twojej metodzie / klasie.

To powiedziawszy, że musisz również przetestować w „prawdziwym” repozytorium *, ale zwykle odbywa się to w teście integracji / systemu

* oczywiście prawdziwe jak w repozytorium skonfigurowanym do testu, mam nadzieję, że nie np. produkcyjna baza danych.

jk.
źródło
Więc w testach jednostkowych nie będę testował samej metody, aby upewnić się, że zwraca prawidłowe wartości (na podstawie fałszywego / fałszywego zestawu danych)?
jao
tak, przetestujesz samą metodę, ale tylko kod w metodzie, kod w innych obiektach powinien być objęty innymi testami jednostkowymi, interakcja wielu obiektów powinna być objęta testami integracji lub testami wyższego poziomu
jk.
1
Ok, więc jeśli dobrze rozumiem, powinienem używać oryginalnego repozytorium podczas testowania repozytoriów przez jednostkę. I nie trzeba testować je, gdy piszę jednostki badań dla kontrolerów (w przypadku ASP.NET MVC)
jao
4
@Theomax Zależy od kontekstu: jeśli testujesz jednostkę komponentu programowego, który nie jest twój ExampleRepository, najlepiej użyć próbnego. Uzasadnieniem jest to, że nie przeprowadzasz testów jednostkowych repozytorium, ale coś innego.
Andres F.,
5
@ Theomax Aby rozwinąć komentarz AndresF .: Jeśli przeprowadzasz testy jednostkowe ExampleRepository, użyj prawdziwej rzeczy. Jeśli przeprowadzasz testy jednostkowe RepositoryController, powinieneś użyć tylkoFakeExampleRepository tego, który zwraca wstępnie określone wartości. W ten sposób, jeśli wkradnie się błąd ExampleRepository, tylko ten test jednostkowy zakończy się niepowodzeniem - RepositoryControllertesty będą nadal udane, więc wiesz, że nie ma tam błędu. Jeśli kontroler użył prawdziwego repozytorium, że zarówno one być zawodzi, a ty nie wiesz, gdybyś miał 1 błąd lub 2.
Izkata
5

Zgadzam się z dwiema odpowiedziami jk. i Jan Hudec - dają naprawdę dobre informacje. Ale pomyślałem, że dodałbym trochę.

Twoje pierwsze pytanie („Jaki dokładnie jest tutaj cel?”) Jest ważne. W opisywanym przypadku prawdziwym celem jest przetestowanie klas korzystających z IExampleRepositoryinterfejsu, a nie testowanie implementacji repozytorium. Utworzenie FakeExampleRepositorypozwala przetestować te klasy klienta bez obawy o szczegóły prawdziwej klasy repozytorium.

Jest to szczególnie prawdziwe, jeśli obiekt, który próbujesz skonfigurować, utrudnia testowanie (np. Uzyskuje dostęp do systemu plików, wywołuje usługę internetową lub rozmawia z bazą danych). Używając interfejsów (i innych takich technik), utrzymujesz niskie sprzężenie. Dlatego klasa Xmusi tylko wiedzieć o interfejsie i nie musi znać szczegółów implementacji. Celem jest upewnienie się, że klasa Xpostępuje właściwie.

Wyśmiewanie (lub karczowanie, fałszowanie ... są różne różnice) to potężne narzędzie do testowania jednostek i TDD. Jednak ręczne tworzenie i utrzymywanie tych implementacji może być uciążliwe. Dlatego większość języków ma teraz kpiące biblioteki do pomocy. Ponieważ używasz C #, polecam Moq, ponieważ jest prosty i bardzo wydajny. Następnie możesz przetestować interfejs bez gromadzenia dodatkowego kodu dla próbnych implementacji.

Allan
źródło
the real objective is to test the classes that are utilizing the IExampleRepository interfaceto nie jest do końca prawda. Celem jest przetestowanie go niezależnie od IExampleRepository. +1 za zalecenie dobrych ram izolacji.
StuperUser
1
Nie zgadzam się. Nie jest to niezależne, IExampleRepositoryponieważ testowana klasa jest sprzężona z tym interfejsem. Ale jest niezależny od jakichkolwiek implementacji interfejsu. Przyznaję, że moje wyjaśnienie przydałoby się nieco bardziej finezji. :)
Allan
5

Jaki jest tutaj dokładnie cel?

Izolacja.

Pomysł jednostki przetestuj ją, aby przetestować najmniejszą możliwą jednostkę kodu. Robisz to, izolując go od wszystkich innych kodów produkcyjnych w teście.

Tworząc fałszywe klasy jedynym kodem produkcyjnym jest klasa testowana.

Jeśli poprawnie utworzysz fałszywe repozytorium, a test się nie powiedzie, wiesz, że problem dotyczy testowanego kodu. Zapewnia to bezpłatną diagnozę.

Spójrz na struktury izolacyjne (takie jak Moq, jak sugeruje @Allan), aby móc szybko wygenerować te podróbki, aby skonfigurować warunki testowe i użyć ich do potwierdzenia.

StuperUser
źródło
Więcej szczegółów na temat podróbek, makiet i artykułów: stackoverflow.com/questions/346372/…
StuperUser
4

Istnieją trzy powody, dla których warto udostępnić próbną instancję do testu jednostkowego:

  1. Chcesz ograniczyć zakres testu, aby na test nie miały wpływu błędy w depndee, być może dlatego, że nie jest on jeszcze ukończony lub nie jest stabilny lub nie chcesz, aby błędy w innych wpływały na twoje testy.
  2. Konfiguracja osoby zależnej jest skomplikowana. Na przykład warstwa dostępu do danych jest często wyśmiewana, ponieważ prawdziwa wymaga skonfigurowania testowej bazy danych. Nadal musisz przetestować rzeczywistą warstwę dostępu do danych, ale możesz ograniczyć kosztowną konfigurację podczas debugowania innych rzeczy.
  3. Aby przetestować, czy klasa zależna poprawnie reaguje na różnego rodzaju błędy, podajesz próbną wersję, która zwraca różnego rodzaju błędne odpowiedzi. Ponieważ wiele trybów awarii jest raczej trudnych do odtworzenia, ale wciąż należy je przetestować.
Jan Hudec
źródło