Mam wiele metod logiki biznesowej, które przechowują i pobierają (z filtrowaniem) obiekty i listy obiektów z pamięci podręcznej.
Rozważać
IList<TObject> AllFromCache() { ... }
TObject FetchById(guid id) { ... }
IList<TObject> FilterByPropertry(int property) { ... }
Fetch..
i Filter..
zadzwoniłby, AllFromCache
który zapełni pamięć podręczną i zwróci, jeśli nie ma, i po prostu wróci z niej, jeśli tak jest.
Zasadniczo unikam testów jednostkowych. Jakie są najlepsze praktyki dotyczące testowania jednostkowego w przypadku tego typu konstrukcji?
Zastanawiałem się nad zapełnieniem pamięci podręcznej w TestInitialize i usunięciem w TestCleanup, ale to nie wydaje mi się właściwe (może tak być).
źródło
Zasada pojedynczej odpowiedzialności jest tutaj twoim najlepszym przyjacielem.
Przede wszystkim przenieś AllFromCache () do klasy repozytorium i nazwij ją GetAll (). To, że pobiera z pamięci podręcznej, jest szczegółem implementacji repozytorium i nie powinno być znane kodowi wywołującemu.
To sprawia, że testowanie klasy filtrowania jest przyjemne i łatwe. Nie zależy już na tym, skąd go bierzesz.
Po drugie, owiń klasę, która pobiera dane z bazy danych (lub gdziekolwiek) w opakowanie buforujące.
AOP jest do tego dobrą techniką. To jedna z niewielu rzeczy, w których jest bardzo dobra.
Korzystając z narzędzi takich jak PostSharp , możesz to ustawić tak, aby każda metoda oznaczona wybranym atrybutem była buforowana. Jeśli jednak to jedyna rzecz, którą buforujesz, nie musisz sięgać tak daleko, jak posiadanie frameworka AOP. Wystarczy mieć repozytorium i opakowanie buforujące, które używają tego samego interfejsu i wstrzyknąć to do klasy wywołującej.
na przykład.
Zobacz, jak usunąłeś wiedzę dotyczącą implementacji repozytorium z menedżera produktów ProductManager? Zobacz także, w jaki sposób przestrzegałeś zasady pojedynczej odpowiedzialności, mając klasę, która obsługuje ekstrakcję danych, klasę, która obsługuje odzyskiwanie danych oraz klasę, która obsługuje buforowanie?
Możesz teraz utworzyć instancję menedżera produktu ProductManager z jednym z tych repozytoriów i uzyskać buforowanie ... lub nie. Jest to niezwykle przydatne później, gdy pojawi się mylący błąd, który, jak podejrzewasz, jest wynikiem pamięci podręcznej.
(Jeśli używasz kontenera IOC, nawet lepiej. Powinno być oczywiste, jak się przystosować.)
I w testach ProductManager
W ogóle nie trzeba testować pamięci podręcznej.
Teraz pojawia się pytanie: czy powinienem przetestować to CachedProductRepository? Sugeruję nie. Pamięć podręczna jest dość nieokreślona. Framework robi z nim rzeczy, które są poza twoją kontrolą. Na przykład po prostu usuwam z niego rzeczy, gdy się zapełni, na przykład. Skończysz z testami, które zawiodą raz na niebieskim księżycu i nigdy tak naprawdę nie zrozumiesz, dlaczego.
Po wprowadzeniu zmian, które zasugerowałem powyżej, naprawdę nie ma zbyt wiele logiki do przetestowania. Naprawdę ważny test, metoda filtrowania, będzie tam i całkowicie oderwany od szczegółów GetAll (). GetAll () po prostu ... dostaje wszystko. Skądś.
źródło
Twoje sugerowane podejście jest tym, co bym zrobił. Biorąc pod uwagę twój opis, wynik metody powinien być taki sam, niezależnie od tego, czy obiekt jest obecny w pamięci podręcznej, czy nie: nadal powinieneś uzyskać ten sam wynik. Łatwo to przetestować, konfigurując pamięć podręczną w określony sposób przed każdym testem. Prawdopodobnie istnieją dodatkowe przypadki, na przykład gdy guid jest
null
lub żaden obiekt nie ma żądanej właściwości; te też można przetestować.Dodatkowo, ty może uznać, że oczekuje się, że obiekt będzie obecny w pamięci podręcznej po powrocie metody, niezależnie od tego, czy w ogóle był w pamięci podręcznej. Jest to kontrowersyjne, ponieważ niektórzy ludzie (w tym ja) twierdzą, że zależy ci na tym , co otrzymasz z interfejsu, a nie na tym , jak go uzyskasz (tj. Na testowaniu, czy interfejs działa zgodnie z oczekiwaniami, a nie że ma określoną implementację). Jeśli uznasz to za ważne, masz okazję to przetestować.
źródło
W rzeczywistości jest to jedyny właściwy sposób. Do tego służą te dwie funkcje: ustalenie warunków wstępnych i oczyszczenie. Jeśli warunki wstępne nie zostaną spełnione, Twój program może nie działać.
źródło
Pracowałem ostatnio nad niektórymi testami, które używają buforowania. Utworzyłem opakowanie wokół klasy, które działa z pamięcią podręczną, a następnie miałem zapewnienia, że to opakowanie zostało wywołane.
Zrobiłem to głównie dlatego, że istniejąca klasa, która działa z pamięcią podręczną, była statyczna.
źródło
Wygląda na to, że chcesz przetestować logikę buforowania, ale nie logikę zapełniającą. Proponuję więc kpić z tego, czego nie trzeba testować - wypełniania.
Twoja
AllFromCache()
metoda zajmuje się zapełnianiem pamięci podręcznej i należy ją przekazać innej osobie, na przykład dostawcy wartości. Tak wyglądałby twój kodTeraz możesz wyśmiewać dostawcę do testu, aby zwrócić niektóre wstępnie zdefiniowane wartości. W ten sposób możesz przetestować faktyczne filtrowanie i pobieranie, a nie ładowanie obiektów.
źródło