Testy integracyjne. Co i jak?

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.

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

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.

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ść.

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?

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

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

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ść?

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.

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 :-)

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