Testy

tests

Jest pięknie

Żeby zgrabnie było, trzeba popróbować i tak ułożyć i siak ułożyć i sprawdzić i obejrzeć i posmakować. Ja chciałem wam opisać krótko jak sobie ułożyłem testy w projekcie i póki co mi podoba taki układ.

Od góry

Zaczynając od samej solucji:
2016-06-05 12_24_19-Itan (Running) - Microsoft Visual Studio (Administrator)

Na testy przeznaczyłem osobny folder, a projekt nazywa się tak samo jak projekt który chce testować, rozszerzony o Tests. Myślę, że większość z was robi tak samo.

Dalej wygląda to tak:
2016-06-05 12_29_39-Itan (Running) - Microsoft Visual Studio (Administrator)
Kolejne podfoldery odpowiadają klasom, które będę testować plus dodatek Tests:

  • ApplicationLoginServiceTests
  • OpmlImporterServiceTests
  • RssChannelServiceTests

Niżej są poszczególne metody, które będą testowane. Każdej metodzie dedykuje plik, a w środku całą klasę.

Mięso

Poniżej przykładowa klasa:

Jak widzicie, jeśli czytacie to jeszcze, jedna metoda jest testowana na kilka sposobów i sprawdzane są różne rzeczy.

Konwencja

Oprócz tego wprowadziłem konwencje nazewniczą, które zaczyna się od T, a następnie kilku cyferek. Usprawnia to przede wszystkim ogarnianie dużej ilości testów, a w szczególności gdy któryś test się położy i trzeba się porozumieć. Dużo lepiej sprawdza się, gdy przekazuje się informację, że test 058_nie_ważne nie działa, niż When_Blah_Blah_Then_Blah_Blah_BLAH.

Trzy literowy skróty

Staram się także pilnować podejścia Given-When-Then. Gdzie Given to klasa, a When-Then zawiera się w nazwie metody.

I ostatnia rzecz, to AAA. Arrange-Act-Assert;
Czyli arrange – część przygotowania systemu do aplikacji, act – wykonanie właściwego kodu, który będzie testowany, oraz assert – sprawdzenie czy wszystko poszło poprawnie.

Część mówi, że powinien być tylko jeden assert w teście. Jasne, ale moja interpretacje mówi, że to ma być assert logiczny. Ja to rozumiem jako sprawdzanie wszystkiego co dotyczy wcześniej wykonanej operacji, tyle asertów ile potrzeba, ale wszystkie muszą być związane z tą właśnie jedną operacją, jeden asert.

Następnym razem o 100%

12 thoughts on “Testy

  1. Z numeracją testów jeszcze się nie spotkałem. Powiem szczerze, że bardzo nie podoba mi się to, ponieważ trzeba potem pilnować kolejności.
    Druga rzecz. Jeśli komuś powiesz, że test T085 nie działa, to co z tego. I tak zwyczajowo powinien odpalić wszystkie testy i zobaczyć czy tylko ten jeden test nie działa.

    Reasumując, nie widzę korzyści z numeracji testów, a kolejności trzeba później pilnować.

    1. Kolejność nie jest obowiązkowa. Chodzi raczej o szybszą metodę zidentyfikowania testu, z jednoczesnym zachowaniem czytelności i „opisowości” nazwy testu. Moje rozwiązania nie muszą i pewnie nie są rozwiązaniami dla wszystkich. Nie mówię, że moje rozwiązanie jest to jedynym. Staram się pokazać kolejne rozwiązanie, które może kiedyś komuś się przyda.

  2. Szczerze mówiąc też średnio podoba mi się numerowanie testów. Z jednej strony wprowadza to porządek, ale z drugiej strony sugeruje kolejność testów. A testy nie powinny być puszczane w kolejności. Najlepszy scenariusz to taki kiedy były by puszczane w losowej kolejności.

    1. Numerowanie ma na celu tylko i wyłącznie usprawnienie komunikacji. I w zasadzie prościej też odnaleźć taki test w R# runnerze, który układa je alfabetycznie. Ale macie racje, że na pierwszy rzut oka, dla osób nowych w projekcie, nie zaznajomionych z konwencją może, a pewnie nawet sugeruje to, że testy muszą się wykonać z tej właśnie kolejności. Gdzie oczywiście masz rację, tak nigdy nie może się zdarzyć.
      Natomiast jeśli chodzi o numeracji, to fajnie jeśli cyferki się nie powtarzają i tyle.
      I napiszę jeszcze raz: u mnie się to rozwiązanie sprawdza i jeśli mogę i zespół to kupuje, to wprowadzam. Jeśli są obiekcje, to nic na siłę.

  3. Pingback: dotnetomaniak.pl
  4. Myślę, że te fragmenty kodu oznaczone komentarzami arrange i act to powinno się od razu wydzielać do oddzielnych metod, bo aż rzucają się w oczy te copy-pastowe powtórzenia kodu 😉

    1. Tak i nie, tak: bo powtarzanie się nie jest sexy. Nie – ponieważ każdy z testów chce, aby był zupełnie samodzielny. Jeśli wydzielę część wspólną, to wtedy każda zmiana może mieć wpływ na inne testy. Np. mogę w jakimś arrange robić więcej, bo test 001 tego wymaga, ale będzie to za dużo dla testu 002.
      Dla mnie kod w testach rządzi się odrobinę innymi regułami, jasne – musi być dobry i czysty, ale zgadzam się na pewnego rodzaju ustępstwa.

  5. Nie uważasz że współdzielenie OpmlImporterService i mocków per testy jest niebezpieczne?
    XUnit domyślnie odpala testy równolegle, dlatego takie współdzielenie jest mocno ryzykowne…

    Tworzenie pliku dla poszczególnej metody? Nie widzę tego w większym projekcie 🙂

    1. U mnie testy odpalane są w R# runnerze i nie stwierdziłem uruchamiania ich równolegle. Poza tym, jak mi się wydaje i jak rozumiem, każdy „setup” tworzy instancje od nowa, także każdy jedzie na swoim.

      Plik per metoda – znowu, u mnie to działa. W dużych projektach, gdy w jednym pliku masz testy do całej klasy. A nie oszukujmy się, w komercyjnych projektach klasy są najczęściej większe niż na jeden ekran, metody często także. To w takiej sytuacja klasy testowy będą prze-O-gromne, miałem i nie podobało mi się. Dlatego teraz testuje takie podejście i póki co jestem na tak.

  6. A propos jednej asercji – bardzo dobrze, że poruszyłeś ten temat. Zgadzam się z Tobą w 100%. Problem jest jednak taki, że pewnego pięknego dnia, jeden ze znanych programistów powiedział 1 assert per test – i niestety wielu programistów nie zrozumiało, że chodzi o logiczną asercję (skrót myślowy). I teraz otwierasz kod, a tam sajgon – pierdyliard powtarzających się testów z 1 assertem wewnątrz 🙂

Dodaj komentarz