Testy integracyjne. Co i jak?

Odpowiedz Nowy wątek
2019-05-13 11:00
0

Hej, to moje pierwsze podejście do testów integracyjnych i chciałbym się dowiedzieć jak to prawidłowo robić i jakie mam błędy w rozumieniu tematu. Sporo na ten temat przeczytałem, ale nie wszystko jest dla mnie jasne.

Z testami jednostkowymi mam prosto:
na każdy projekt (który podlega testom jednostkowym) jest jeden projekt testowy. Jeden plik testuje jedną klasę, np:

- solution
    - source
        + ModelsProject
        + ClientProject
    - tests
      - unitTests
        - ModelsTestProject
            Model1Tests.cs
            Model2Tests.cs
            Model3Tests.cs
        - ClientTestProject
          ...

Do takiej hierarchii można to uprościć. To mi się sprawdza, jest przejrzyste i działa. I super. Jednak teraz chciałbym dołożyć testy integracyjne i nie za bardzo wiem, jak się do tego zabrać. Rozumiem, że tutaj działamy na żywym organizmie. Mockowanie ograniczam właściwie jedynie do interakcji z użytkownikiem (np. okna dialogowe). Baza danych to SQLite w pamięci. Tylko nie za bardzo teraz wiem, jak to zrobić dobrze. Miałem już kilka podejść, jednak za każdym razem mam nieodparte wrażenie, że coś robię źle.

Ja wiem, że to zależy głównie od systemu, ale jak tutaj powinna wyglądać taka hierarchia projektów i klas? No bo projekt testowy na jeden projekt w solucji (tak jak mam przy testach jednostkowych) w tym momencie jest bez sensu. Bo projekty współdziałają ze sobą. Więc Wpadłem na pomysł, żeby dać różne projekty na testowanie różnych klientów. Np: WpfIntegrationTests, XamarinIntegrationTests, WebIntegrationTests... Wydaje się to logiczne. Więc idźmy dalej. Co tak naprawdę powinienem testować? W tym momencie zacząłem od testów WpfClient i MainViewModelu. Jednak szybko okazało się, że w MainViewModel nie mam tak naprawdę za wiele do testowania, bo większość akcji jest na poziomie innych viewmodeli. Ale to chyba nie jest problem.

Kolejnym problemem jest co i jak testować. Przykładowo podczas unit testów tworzę sobie metody w standardowym stylu:

public void AddItem_ItemIsNull_ThrowArgumentNullException()
{
//
}

public void AddItem_ItemIsNotNull_AddsItem()
{
//
}

public void AddItem_ItemIsNotNull_AddsItem()
{
//
}

itd. czyli testuję brzegowe wartości, jakieś wartości, które są ok i jakieś wartości, które są nie ok (np. item = null).

Jeśli chodzi o testy integracyjne, to czytam różne rzeczy. Że tu testujemy np. tylko happy path. Czy to jest reguła? Czy też powinienem testować podanie np. niepoprawnych wartości? No i jak nazywać takie metody?

public void CreateDocumentTest()
{
//
}

public void SaveDocumentTest()
{
//
}

public void LoadDocumentTest()
{
//
}

Czy jakoś inaczej? Jak to robicie? Jakie macie doświadczenia i jakie systemy sobie wypracowaliście? I czy używacie do tego innej biblioteki niż do jednostkowych? Ja do wszystkiego używam nUnit.

Pozostało 580 znaków

2019-05-13 11:41
0

Nie do końca wiem w czym robisz, ale baza danych też musi być właściwa z tym że jest to inna baza, przeznaczona tylko na testy i po każdym teście wraca do stanu sprzed testu np trzymając wszystkie operacje w transakcji lub po każdym teście uruchamiając refresh na migracjach. Innymi słowy, jeśli projekt ma być używany z mysql to musisz robić testy na mysql a nie na sqllitle

edytowany 2x, ostatnio: mr_jaro, 2019-05-13 11:42
Pokaż pozostałe 5 komentarzy
@Juhas: zazwyczaj wypełniasz danymi specjalnymi, np robisz usera [email protected] a próbujesz się zalogować na [email protected] i patrzysz czy dostajesz 422. Ty musisz mieć takie dane w bazie w danym konkretnym teście aby sprawdzić to co chcesz sprawdzić. - mr_jaro 2019-05-14 12:20
No tak, to rozumiem. Ale jeśli chcę dodać rekord do tabeli, no to tabela może być pusta, tak? Chyba że chcę testować unikalność kluczy, ale to bez sensu :) - Juhas 2019-05-14 12:35
@Juhas: baza musi być taka jaka będzie po oddaniu do produkcji gdy jeszcze żaden user nic nie kliknął, nie pojawiła się żadna treść. Po czym wypełniasz baze danymi które mają być by zrobić konkretny test, test się wykonuje, po teście leci rollback. Już to pisałem wcześniej. - mr_jaro 2019-05-14 12:43
No tak, po oddaniu do produkcji większość tabel będzie pustych. Rozumiem, że muszę wypełnić resztę. - Juhas 2019-05-14 13:50
@Juhas: tylko te które potrzebujesz w konkretnym teście i tylko na czas konkretnego testu. - mr_jaro 2019-05-14 13:57

Pozostało 580 znaków

2019-05-13 21:36
13

Dawno temu miałem takie rozkminy, ale mi przeszło.
Przestałem jakoś specjalnie rozróżniać testy integracyjne.

Testy to testy:

  1. podaję warunki początkowe,
  2. zapuszczam działanie,
  3. sprawdzam wynik.

Czy po drodze (punkt 1) wypełniam jakąs hashmapę, czy 4 bazy danych to już szczegół implementacyjny.

Bywa, że ze względów praktycznych trzeba wydzielić inicjalizację bazy danych, żeby nie robić przed każdym testem (i wtedy rollbacki po teście).
Bywa, że trzeba dłuzej trwające testy jakoś oznaczyć, by ich np. nie odpalać za każdym razem u programisty.

Ale to są szczegóły.


Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
edytowany 1x, ostatnio: jarekr000000, 2019-05-13 21:37
Pokaż pozostałe 50 komentarzy
Roy Oshorove. The Art Of Unit Test Edit 2. Przeczytaj rozdziały 1.1 - 1.6. Kent Beck wspominał też w ostatnim rozdziale o nadwrażliwości testów i testach długotrwałych. - Gworys 2019-05-14 18:26
6 rodziałów potrzeba, by zdefiniować unit test? Grubo. - Wibowit 2019-05-14 18:58
Zapewne jest to wersja dla tych apodyktycznych :D - Gworys 2019-05-14 19:00
Google zwraca "No results found for apodeptycznych". Książkę Kenta Becka przeczytałem w całości. Całkiem spoko. - Wibowit 2019-05-14 19:01
Przepraszam - apodyktyczny. - Gworys 2019-05-14 19:06

Pozostało 580 znaków

2019-05-14 07:19
1

Pisanie dobrych testów wynika przede wszystkim ze zrozumienia architektury.

W większości przypadków można uniknąć stub'a, czy mock'a wydzielając testowaną logikę do np. klasy statycznej.

To czy piszesz klasę z testami dla metody czy innej klasy to już zależy od twojej kreatywności. Ja lubie np. Partiale używać na inną ścieżke testów.

Ktoś tam coś mówił o słowniku. Co to znaczy mockować? :D

Na poważnie to kiedy ludzie zaczną odróżniać mock od stuba i fake.?

Nie ma nic złego w odróżnianiu testów. :P Tyle że pisanie samych testów integracyjnych, jest w większości przypadków słabe. Lepiej od razu pisać Funkcyjne/Akceptacyjne w stylu BDD z konkretnym label'em pod funkcjonalność.


Unhandled Exception: System.MissingMethodException: Constructor on type 'System.Exception' not found.
edytowany 1x, ostatnio: Gworys, 2019-05-14 07:46
NIe wiem o czym piszesz jeśli chodzi o Partiale. Co do reszty się zgadzam. Dokładnie myśle zawsze o funkcjonalności i często piszę zupełnie w stylu BDD, z tym, że na wszystkich poziomach, warstwach. Poniekąd warstwa wyższa jest klientem warstwy niższej i wymaga od niej spełniania pewnych właściwości, które można opisac np. w stylu BDD. I tak do końca. NIe bardzo wiadomo, w którym miejscu te testy zmieniają się z integracyjnych na 'unity'. - jarekr000000 2019-05-14 08:42
Co do mock, stub, fake - to fakt. Praktycznie nigdy nie używam mocków. Używam niestety potocznego, niepoprawnego nazewnictwa. Praktycznie to Tylko fake (są wyjątki, ale rzadkie) i to zarówno w testach jak i na produkcji. Produkcja to po prostu te fake implementacje, które spełniają wszystkie testy akceptacyjne :-) - jarekr000000 2019-05-14 08:43
Ja wolę odróżniać stub od mock uważam, że testy wtedy zyskują na czytelności. - Gworys 2019-05-14 09:04
Partial to jedna klasa w dwóch plikach. - Gworys 2019-05-14 09:08
W ogólę nie lubię używać mocków, wyjątki to bardzo średnio zrobione zależności zewnętrzne, które tylko tak można przetestować. Raczej nie rozróżniam za to stub i fake. Stub to po prostu fake z trywialnymi implementacjami. Nie widze po co to rozróżnienie. - jarekr000000 2019-05-14 09:11
No fake to tylko implementacja na potrzeby testów, która może być stub'em ewentualnie mock'iem :D - Gworys 2019-05-14 09:17

Pozostało 580 znaków

2019-05-14 08:49
1
Gworys napisał(a):

...
Na poważnie to kiedy ludzie zaczną odróżniać mock od stuba i fake.?
..

Tak, z ciekawości, gdzie jest wartość dodana w nazywaniu na różne sposoby (mock, stub, fake) implementacji użytej na potrzeby testów ?
To nie jest tak jak z tym dowcipem o juhasach i bacy, który rozwiewa wątpliwości jak nazywać jeża poprawnie?

Pozostało 580 znaków

2019-05-14 09:02
0
yarel napisał(a):
Gworys napisał(a):

...
Na poważnie to kiedy ludzie zaczną odróżniać mock od stuba i fake.?
..

Tak, z ciekawości, gdzie jest wartość dodana w nazywaniu na różne sposoby (mock, stub, fake) implementacji użytej na potrzeby testów ?
To nie jest tak jak z tym dowcipem o juhasach i bacy, który rozwiewa wątpliwości jak nazywać jeża poprawnie?

Jeśli ktoś mówi na rower samochód, to zwykle są ku temu tylko dwa powody, ale to może być subiektywne odczucie, więc bym się tym zbytnio nie przejmował. :P


Unhandled Exception: System.MissingMethodException: Constructor on type 'System.Exception' not found.
edytowany 1x, ostatnio: Gworys, 2019-05-14 09:06

Pozostało 580 znaków

2019-05-14 09:13
2
Gworys napisał(a):

Jeśli ktoś mówi na rower samochód, to zwykle są ku temu tylko dwa powody, ale to może być subiektywne odczucie, więc bym się tym zbytnio nie przejmował. :P

powód pierwszy:
rower.jpg


Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
Poddaje się. - Gworys 2019-05-14 09:15

Pozostało 580 znaków

2019-05-14 09:16
1
Gworys napisał(a):
yarel napisał(a):
Gworys napisał(a):

...
Na poważnie to kiedy ludzie zaczną odróżniać mock od stuba i fake.?
..

Tak, z ciekawości, gdzie jest wartość dodana w nazywaniu na różne sposoby (mock, stub, fake) implementacji użytej na potrzeby testów ?
To nie jest tak jak z tym dowcipem o juhasach i bacy, który rozwiewa wątpliwości jak nazywać jeża poprawnie?

Jeśli ktoś mówi na rower samochód, to zwykle są ku temu tylko dwa powody, ale to może być subiektywne odczucie, więc bym się tym zbytnio nie przejmował. :P

Cóż, różnica jest taka, że tu mamy zdefiniowany jasno kontekst (testy i implementacja na potrzeby testów), a w Twoich rozważaniach o rowerach i samochodach jakoś tego kontekstu nie wskazujesz. Obydwa są pojazdami, obydwa mogą być kupione itd.

W code review, takie rozróżnianie, u co bardziej zapalczywych jednostek, może prowadzić do patalogii typu: "nazwałeś plik FooStub, a to jest przecież FooMock" i tym samym odrywać ludzi od rozwiązywania właściwych problemów.

Gdzie, to rozróżnianie nazewnictwa implementacji w testach przynosi korzyść?

edytowany 1x, ostatnio: yarel, 2019-05-14 09:16

Pozostało 580 znaków

2019-05-14 09:21
0
yarel napisał(a):
Gworys napisał(a):
yarel napisał(a):
Gworys napisał(a):

...
Na poważnie to kiedy ludzie zaczną odróżniać mock od stuba i fake.?
..

Tak, z ciekawości, gdzie jest wartość dodana w nazywaniu na różne sposoby (mock, stub, fake) implementacji użytej na potrzeby testów ?
To nie jest tak jak z tym dowcipem o juhasach i bacy, który rozwiewa wątpliwości jak nazywać jeża poprawnie?

Jeśli ktoś mówi na rower samochód, to zwykle są ku temu tylko dwa powody, ale to może być subiektywne odczucie, więc bym się tym zbytnio nie przejmował. :P

Cóż, różnica jest taka, że tu mamy zdefiniowany jasno kontekst (testy i implementacja na potrzeby testów), a w Twoich rozważaniach o rowerach i samochodach jakoś tego kontekstu nie wskazujesz. Obydwa są pojazdami, obydwa mogą być kupione itd.

W code review, takie rozróżnianie, u co bardziej zapalczywych jednostek, może prowadzić do patalogii typu: "nazwałeś plik FooStub, a to jest przecież FooMock" i tym samym odrywać ludzi od rozwiązywania właściwych problemów.

Gdzie, to rozróżnianie nazewnictwa implementacji w testach przynosi korzyść?

Ja bije do tego, że jeśli nie potrafisz, odróżnić jednego od drugiego to jest źle. To czy dopisujecie do nazwy stub, czy dummy, spy etc... To już problem spójnej konwencji, jaką przyjęliście.

Uważam również, że w komunikacji codziennej, kiedy mówimy o testach powinniśmy odróżniać stub od mock'a, ponieważ zmienia to kontekst wypowiedzi.

Gdzie, to rozróżnianie nazewnictwa implementacji w testach przynosi korzyść?

Tam gdzie czytelność testów ma znaczenie.


Unhandled Exception: System.MissingMethodException: Constructor on type 'System.Exception' not found.
edytowany 3x, ostatnio: Gworys, 2019-05-14 09:30

Pozostało 580 znaków

2019-05-14 09:42
1
Gworys napisał(a):

...

Gdzie, to rozróżnianie nazewnictwa implementacji w testach przynosi korzyść?

Ja bije do tego, że jeśli nie potrafisz, odróżnić jednego od drugiego to jest źle. To czy dopisujecie do nazwy stub, czy dummy, spy etc... To już problem spójnej konwencji, jaką przyjęliście.

Uważam również, że w komunikacji codziennej, kiedy mówimy o testach powinniśmy odróżniać stub od mock'a, ponieważ zmienia to kontekst wypowiedzi.

Ok, rozumiem Twój punkt widzenia.

Gdzie, to rozróżnianie nazewnictwa implementacji w testach przynosi korzyść?

Tam gdzie czytelność testów ma znaczenie.

Ten argument jest dość ogólny, bo czytelność kodu jest raczej powszechnie pożądaną cechą. Brakuje mi tu jednak jakiegoś powiązania między czytelność kodu i rozróżnianiem różnych implementacji. Masz jakieś przykłady, gdzie zmiana nazewnictwa jakoś istotnie wpłynęła na czytelność testów? np. "ServiceTestImpl zamieniliśmy na ServiceMockImpl i to uporządkowało nam testy". Nie wiem, dlatego dopytuję celem aktualizacji bazy wiedzy :-)

Pozostało 580 znaków

2019-05-14 10:00
0
yarel napisał(a):
Gworys napisał(a):

...

Gdzie, to rozróżnianie nazewnictwa implementacji w testach przynosi korzyść?

Ja bije do tego, że jeśli nie potrafisz, odróżnić jednego od drugiego to jest źle. To czy dopisujecie do nazwy stub, czy dummy, spy etc... To już problem spójnej konwencji, jaką przyjęliście.

Uważam również, że w komunikacji codziennej, kiedy mówimy o testach powinniśmy odróżniać stub od mock'a, ponieważ zmienia to kontekst wypowiedzi.

Ok, rozumiem Twój punkt widzenia.

Gdzie, to rozróżnianie nazewnictwa implementacji w testach przynosi korzyść?

Tam gdzie czytelność testów ma znaczenie.

Ten argument jest dość ogólny, bo czytelność kodu jest raczej powszechnie pożądaną cechą. Brakuje mi tu jednak jakiegoś powiązania między czytelność kodu i rozróżnianiem różnych implementacji. Masz jakieś przykłady, gdzie zmiana nazewnictwa jakoś istotnie wpłynęła na czytelność testów? np. "ServiceTestImpl zamieniliśmy na ServiceMockImpl i to uporządkowało nam testy". Nie wiem, dlatego dopytuję celem aktualizacji bazy wiedzy :-)

Trochę mi to przypomina porównywanie repozytoriom do DAO.
A czym twoim zdaniem różni się Stub od Mock. Może rzeczywiście, jeśli nie widać różnicy to nietrzeba używać innej nazwy...?


Unhandled Exception: System.MissingMethodException: Constructor on type 'System.Exception' not found.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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

Robot: CCBot, Xenu Link Sleuth