Wątek przeniesiony 2017-09-25 22:08 z C# i .NET przez somekind.

Granica między testami integracyjnymi a jednostkowymi

0

Jeśli chcesz przetestować jakąś logikę, której częścią jest trzymanie danych w bazie i użyjesz w tym celu SQLite, to to nadal będzie to test integracyjny. A jeśli musisz to robić i nie jesteś w stanie przetestować logiki bez źródła danych, to źle to świadczy o architekturze.

Daj przykład.
A jeśli logika to np. Transaction Script i ma metodę typu GetCośZBazyDanych()
To jest to od razu objaw złej Architektury?

0

Jeśli cała logika jest wepchnięta do tego transaction scriptu, to tak. Jeśli zaś ten transaction script pobiera jakieś dane, potem wysyła je do klasy przetwarzającej dane, a potem odbiera wynik i go zapisuje do bazy, to jest ok. Bo klasę przetwarzającą można testować jednostkowo niezależnie od źródła danych, a cały transaction script testuje się integracyjnie.

0
somekind napisał(a):

Jeśli cała logika jest wepchnięta do tego transaction scriptu, to tak. Jeśli zaś ten transaction script pobiera jakieś dane, potem wysyła je do klasy przetwarzającej dane, a potem odbiera wynik i go zapisuje do bazy, to jest ok. Bo klasę przetwarzającą można testować jednostkowo niezależnie od źródła danych, a cały transaction script testuje się integracyjnie.

Czyli kod operujący na ORM powinie być izolowany aby usprawnić testy integracyjne.
No dobra ale jeśli chcę wyświetlić w view wynik zapytania to mogę wstrzyknąć do kontrolera bezpośrednio repozytorium, dao, czy muszę tak jak to większości przypadków widzę zrobić na to wraper w postaci jakiegoś serwisu, który i tak nie ma żadnej logiki..?

0

Widzę że nie chcesz mi odpowiedzieć na ostatnie pytanie.
No więc w inną mańkę jeśli jesteś taki pragmatyczny a w "teorii" transaction script może zawierać prostą logikę.

// w tym przypadku trywialne.
return ORM().RowCount() / 10 + 1

To nie lepiej będzie najpierw stworzyć zaślepkę w postaci ORM w unit teście a potem jeszcze raz to przetestować z testem integracyjnym.
Aby zweryfikować czy problem jest w logice czy w dostępie do bazy.
Zaoszczędzając na dodatkowej warstwie przecież po coś wstrzykuje tego ORM'a.

0

Jeżeli testujesz zapis czy odczyt z bazy, to robienie tego jednostkowo na jakichś mockach nie ma sensu. Nie ma też sensu robienia tego na innej bazie niż docelowa, bo wyniki mogą być różne. Na przykład w sytuacji, gdy docelowa baza ma inną dokładność przechowywania liczb albo dat, więc to co odczytasz nie jest tym, co zapisujesz i czego się spodziewasz.

Czyli jeśli chcę sprawdzić czy ORM wypluł 10 wierszy z 20 (przed chwilą to napisałem i chcę sprawdzić czy działa.) to muszę do tego użyć realnej bazy ? To ma być pragmatyczne ? Co mnie interesuje dokładność liczbowa w zakresie 6 zer. Jak to dokładność przechowywania daty? Chodzi ci o pułapkę milenium? To jakaś baza nie obsługuję UTC I jednego z 4 najpopularniejszych typów formatowania daty? To jak ty zapisujesz tą datę do bazy?

3

Czemu się tak uparłeś że to muszę być testy jednostkowe?
To co chcesz zrobić jest dobre, jest testem, ale nie jednostkowym - i nic tego nie zmieni.

0

Ma znamiona testów jednostkowych, chciałem skonfrontować wszystkie moje wątpliwości. Z waszymi opiniami. Bardzo się cieszę że je skontrowaliście. Jak mi coś jeszcze przyjdzie do głowy to napiszę. OK?

1
MrBean Bean napisał(a):

Czyli kod operujący na ORM powinie być izolowany aby usprawnić testy integracyjne.

Tu nawet nie o testy chodzi, oddzielenie pobierania danych od ich przetwarzania to po prostu stosowanie zasady SRP.

No dobra ale jeśli chcę wyświetlić w view wynik zapytania to mogę wstrzyknąć do kontrolera bezpośrednio repozytorium, dao, czy muszę tak jak to większości przypadków widzę zrobić na to wraper w postaci jakiegoś serwisu, który i tak nie ma żadnej logiki..?

Ciekawe, że piszesz o większości przypadków, bo ja raczej widzę idiotyczne wstrzykiwanie "repozytoriów" bezpośrednio do kontrolerów. Szczęściarz z Ciebie.
Ja bym zrobił serwis, który operuje na sesji ORMa i używał go z kontrolera. Wszelkiego rodzaju testy przy takim podejściu pisze się łatwo.

MrBean Bean napisał(a):

Widzę że nie chcesz mi odpowiedzieć na ostatnie pytanie.

No, to straszne, że nie odpisałem aż przez 49 minut. :D

To nie lepiej będzie najpierw stworzyć zaślepkę w postaci ORM w unit teście a potem jeszcze raz to przetestować z testem integracyjnym.

I jaki zysk da test jednostkowy z zamockowanym ORMem w tak trywialnym przypadku? Żadnego, bo cała logika jest oparta na tym, co faktycznie zwróci baza.

Zaoszczędzając na dodatkowej warstwie przecież po coś wstrzykuje tego ORM'a.

Zgaduję, że wstrzykujesz po to, żeby nie tworzyć zapytań SQL ręcznie.

MrBean Bean napisał(a):

Czyli jeśli chcę sprawdzić czy ORM wypluł 10 wierszy z 20 (przed chwilą to napisałem i chcę sprawdzić czy działa.) to muszę do tego użyć realnej bazy ? To ma być pragmatyczne ?

Tak.
No chyba, że piszesz testy, żeby pisać, a nie po to, żeby się upewnić czy aplikacja działa.

Co mnie interesuje dokładność liczbowa w zakresie 6 zer. Jak to dokładność przechowywania daty? Chodzi ci o pułapkę milenium? To jakaś baza nie obsługuję UTC I jednego z 4 najpopularniejszych typów formatowania daty? To jak ty zapisujesz tą datę do bazy?

Pułapka millenium, mocne. :P
Nie mam pojęcia o jakich 4 typach formatowania mówisz. Generalnie różne SZBD oferują różne typy danych do przechowywania informacji o czasie. Typy te mogą mieć różne dozwolone zakresy i różne dokładności (np. datetime w MSSQL przechowuje dość nietypowo, bo z dokładnością do 1/300 sekundy). I wypadałoby też, aby programista dobrał typ do danych jakie zamierza przechowywać, a nie zawsze wybierał ten "najlepszy", który przy okazji zajmuje najwięcej miejsca i najwolniej się z niego korzysta.
No i teraz, jeśli program zapisze dane do bazy z jakąś dokładnością, ORM je jakoś skonwertuje, a baza narzuci swoje ograniczenia, to może się okazać, że różnice są na tyle istotne, że test na fejkowej bazie przejdzie, a ten na prawdziwej nie. Albo w drugą strone, SQLite może ograniczyć dane bardziej niż prawdziwa baza. A co jeśli problemem nie będzie baza tylko sterownik ORMa do niej będzie miał jakiegoś buga? A do tej drugiej będzie ok? Jednostkowe testy operacji na bazie mają tyle możliwości na bycie fałszywymi, że są po prostu zupełnie bezsensowne.

Nie wiem po co piszesz swoje aplikacje, ale ja po to, żeby działały. A testy piszę po to, żeby upewnić się, czy aplikacja robi to, co chcę żeby zrobiła. Jeśli coś zapisuję, to chcę odczytać to samo. Lepiej gdy sprawdzę to ja niż użytkownicy na produkcji.

0

Tu nawet nie o testy chodzi, oddzielenie pobierania danych od ich przetwarzania to po prostu stosowanie zasady SRP.

Jeśli odpowiedzialność pobieranie danych oraz odpowiedzialność przetwarzanie danych nie jet używana przez aplikacje w różnym czasie to nie ma sensu Ich rozdzielania i nie jest to naruszenie SRP.

Poza tym ORM nie jest izolacją pobierania danych ?
To mam na to jakieś repozytorium robić ?? Uzasadnij dlaczego skoro ORM jest abstrakcją i mogę go moćkować jak repo.

I jaki zysk da test jednostkowy z zamockowanym ORMem w tak trywialnym przypadku? Żadnego, bo cała logika jest oparta na tym, co faktycznie zwróci baza.

A to jakaś nowość że logika przetwarza dane i potrzebuje ich źródła? No ręce mi teraz opadły.

Ja bym zrobił serwis, który operuje na sesji ORMa i używał go z kontrolera. Wszelkiego rodzaju testy przy takim podejściu pisze się łatwo.

Ciekawe, że piszesz o większości przypadków, bo ja raczej widzę idiotyczne wstrzykiwanie "repozytoriów" bezpośrednio do kontrolerów. Szczęściarz z Ciebie.
Ja bym zrobił serwis, który operuje na sesji ORMa i używał go z kontrolera. Wszelkiego rodzaju testy przy takim podejściu pisze się łatwo.

A czym ten serwis będzie się różnił od tego twojego repozytorium oprócz nazwy ?

Zgaduję, że wstrzykujesz po to, żeby nie tworzyć zapytań SQL ręcznie.

A to zabawne.

No, to straszne, że nie odpisałem aż przez 49 minut. :D

Byłeś online i się nie odezwałeś !!...

0
MrBean Bean napisał(a):

Jeśli odpowiedzialność pobieranie danych oraz odpowiedzialność przetwarzanie danych nie jet używana przez aplikacje w różnym czasie to nie ma sensu Ich rozdzielania i nie jest to naruszenie SRP.

:D :D :D

Poza tym ORM nie jest izolacją pobierania danych ?
To mam na to jakieś repozytorium robić ?? Uzasadnij dlaczego skoro ORM jest abstrakcją i mogę go moćkować jak repo.

Nie wiem skąd ten pomysł z repozytorium. Nigdy nikomu jeszcze tego nie poleciłem, każdemu odradzam.

A to jakaś nowość że logika przetwarza dane i potrzebuje ich źródła? No ręce mi teraz opadły.

Widocznie nigdy nie pisałeś niczego więcej niż CRUD.

Byłeś online i się nie odezwałeś !!...

Doprawdy straszne. :D
Masz pięć lat? :D

0

Mam 13 a co ?

Widocznie nigdy nie pisałeś niczego więcej niż CRUD.

A może ty jeszcze nigdy nie napisałeś CRUD'a.

:D :D :D

Co cię tak bawi?

0

Nie wiem skąd ten pomysł z repozytorium. Nigdy nikomu jeszcze tego nie poleciłem, każdemu odradzam.

Tu nawet nie o testy chodzi, oddzielenie pobierania danych od ich przetwarzania to po prostu stosowanie zasady SRP.

No przecież sam to sugerujesz... Aby zrobić serwis a do niego podpiąć repo.

0

Ja cały czas piszę o oddzieleniu przetwarzania danych (czyli logiki/obliczeń), które jest sens testować jednostkowo od reszty kodu (czyli np. skryptu transakcji, który operuje na kontekście ORMa i wywołuje logikę zaimplementowaną w innych klasach.) Jeżeli ktoś z tego wyciąga wniosek, że sugeruję tworzenie jakiś pseudorepozytoriów wrapujących ORMa (które to podejście od zawsze mieszam z błotem), to znaczy, że tak naprawdę nie wyciąga wniosku.

0

To jak? Mam jakiegoś helper'a zrobić do tego transaction script z logiką ? Czyli to tak jakby ropozytorium wołało serwis.?

A to ja mam za modelować tą logikę jako encje a nie serwis ? Czy coś pomieszałem ?

3

Nie ma żadnych repozytoriów. Kontroler woła serwis, a serwis używa ORMa do operacji na danych albo jakichś innych serwisów do obliczeń. To jest prosta architektura sprawdzająca się w wielu przypadkach.

A jak chcesz mieć DDD, to rób repozytoria, logikę w encjach, itd.

0

@somekind: i co wywołujesz zapytania ORM bezpośrednio w serwisach?

1

@scibi92: Owszem.

0

No według mnie lepiej to wydzielić do osobych klas/metod

0

A jak powinno się testować taki serwis operujący bezpośrednio na ORMie?

0

A jak powinno się testować taki serwis operujący bezpośrednio na ORMie?

Integracyjnie serwis z ORM który wywołuje serwis z logiką.
Jednostkowo serwis z logikom.
Dzięki temu nie musisz "moćkować" ORM.
Testowanie Samego ORM w repo nie ma sensu.
Wystarczy tylko jego mapowanie sprawdzić integracyjnie.

Zagadza się, Somekind?

A tak nawiasem mówiąc co sądzicie o Clean Architecture ? Pod względem testowania oraz pochodnych jak hexagon czy onion ?

0

A jak chcesz mieć DDD, to rób repozytoria, logikę w encjach, itd.

To DDD nie może istnieć bez repo ? A do CQRS ma sens repo?

0

@tdudzik: tak, można użyć portów i adapterów. Jak masz taki serwis, o którym ja piszę, wołany przez kontroler (GUI), to nawet prawie masz już zewnętrzne porty. Opisywane przeze mnie podejście sprawdza się w przypadku crudów z logiką. Jeśli logiki jest więcej, to inne archiektury są lepsze.

scibi92 napisał(a):

No według mnie lepiej to wydzielić do osobych klas/metod

Jeśli to samo zapytanie ma być używane w wielu miejscach to tak. Poza tym nie widzę sensu.

mad_penguin napisał(a):

A jak powinno się testować taki serwis operujący bezpośrednio na ORMie?

Skutecznie, czyli najczęściej integracyjnie jeśli chcemy przetestować czy aplikacja zadziała.

MrBean Bean napisał(a):

To DDD nie może istnieć bez repo ? A do CQRS ma sens repo?

Raczej repozytorium nie może istnieć bez DDD.
A co do CQRS to zależy czy jest połączony z DDD czy nie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1