Jaki jest najlepszy sposób na zorganizowanie naszych testów jednostkowych

18

Przez lata opracowaliśmy znaczną liczbę testów jednostkowych dla naszego programu głównego. Kilka tysięcy. Problem polega na tym, że nie mamy jasnego pojęcia, jakie testy mamy, ponieważ jest ich tak wiele. I to jest problem, ponieważ nie wiemy, gdzie jesteśmy słabi w testach (lub gdzie mamy duplikaty).

Nasza aplikacja to silnik raportowania. Możesz mieć szablon, który służy do testowania parsowania (czy czytamy wszystkie właściwości tabeli), scalania danych (czy zachowaliśmy poprawne właściwości tabeli podczas scalania), formatowania końcowej strony (czy tabela jest poprawnie umieszczona na stronie ) i / lub format wyjściowy (czy utworzony plik DOCX jest poprawny).

Dodaj do tego, co musimy przetestować. Rozmieść wypełnienie wokół komórki tabeli (do projektowania raportów używamy Word, Excel i PowerPoint). Musimy przetestować wypełnienie w podziale strony, dla tabeli wewnątrz komórki, pionowo scalonych komórek, poziomo scalonych komórek, pionowo i poziomo scalonej komórki zawierającej tabelę z pionowo i poziomo scalonymi komórkami w wewnętrznej tabeli, gdzie ta tabela psuje się na stronie.

Więc w jakiej kategorii znajduje się ten test? Wypełnianie tabel, podziały stron, zagnieżdżone komórki, pionowo połączone komórki, poziome scalone komórki czy coś innego?

Jak dokumentujemy te kategorie, nazywamy testy jednostkowe itp.?

Aktualizacja: wiele osób zasugerowało użycie narzędzi pokrycia w celu sprawdzenia, czy mamy pełne pokrycie. Niestety w naszym przypadku ma to ograniczone zastosowanie, ponieważ błędy są spowodowane konkretnymi kombinacjami, więc to kod został przetestowany, ale nie w tej kombinacji.

Na przykład mieliśmy wczoraj klienta, który uruchomił zakładkę Word na końcu pętli forEach w swoim szablonie (dokument Word) i zakończył ją na początku następnej pętli forEach. Ten cały używany kod, który ma testy jednostkowe, ale nie pomyśleliśmy o kombinacji szablonu rozszerzającego zakładkę, należy rozpocząć 25 razy, a następnie zakończyć 10 razy (dwie pętle forEach miały inną liczbę wierszy).

David Thielen
źródło
1
Wygląda na to, że twoje pytanie brzmi naprawdę: Skąd wiemy, że przetestowaliśmy konkretny scenariusz?
Andy Wiesendanger,
Tak! A także gdzie są testy dla podobnych scenariuszy. Z tego wynika potrzeba nr 2 - czytanie tego, co jest objęte, pomaga nam znaleźć to, co przegapiliśmy.
David Thielen,

Odpowiedzi:

13

Ogólnie rzecz biorąc, mam tendencję do tworzenia kopii lustrzanej drzewa źródeł dla moich testów jednostkowych. Tak więc, gdybym miał src / lib / fubar, miałbym test / lib / fubar, który zawierałby testy jednostkowe dla fubara.

Wydaje się jednak, że opisujesz więcej testów funkcjonalnych. W takim przypadku miałbym wielowymiarowy stół, który wyliczałby wszystkie możliwe warunki. Zatem te, które nie mają testów, są albo bezsensowne, albo wymagają nowego testu. Możesz oczywiście umieścić je w zestawach zestawów testowych.

Sardathrion - Przywróć Monikę
źródło
Obecnie dublujemy drzewo źródłowe. Ale mamy dwa problemy. Po pierwsze, w przypadku formatowania tabeli istnieje ponad 100 różnych testów. Problemem stało się śledzenie tego, co dokładnie jest testowane. Po drugie, bardzo różne obszary funkcjonalne muszą testować tabele - parsery, podstawianie danych, formatowanie i tworzenie dokumentu wyjściowego. Myślę więc, że masz rację, w pewnym sensie jest to test funkcjonalny danej właściwości.
David Thielen,
Co prowadzi do pytania, gdzie przechowujemy tabelę testów? Myślę, że arkusz kalkulacyjny w głównym katalogu źródłowym ???
David Thielen,
Chciałbym zapisać go w arkuszu kalkulacyjnym z kontrolą wersji w katalogu testowym. Jeśli masz wiele rzeczy, które musisz przetestować, korzystne byłoby rozbicie ich na meta struktury. Spróbuj pomyśleć w kategoriach tego, co jest testowane, zamiast czego i jak.
Sardathrion - Przywróć Monikę
7

Najczęstszą strukturą wydaje się być srci testlustro katalogu.

src/module/class
test/module/class_test

Istnieje jednak alternatywna struktura, którą widziałem, którą teraz uważam za lepszą.

src/module/class
src/module/class_test

Ponieważ testy jednostkowe odzwierciedlają klasę, którą testują, umieszczenie ich w tym samym katalogu zapewnia znacznie łatwiejszy dostęp do plików, dzięki czemu można pracować po obu stronach.

ming_codes
źródło
2
Jedną wadą poprzedniego podejścia jest to, że za każdym razem, gdy decydujesz się zmienić strukturę plików projektu, musisz zrobić to samo dla struktury testów. Ten problem nie istnieje, jeśli testy są tam, gdzie jest kod.
victor175
5

W .NET mam tendencję do tworzenia kopii lustrzanej lub przynajmniej przybliżania struktury przestrzeni nazw dla kodu źródłowego w projektach testowych, pod główną przestrzenią nazw „Tests.Unit” lub „Tests.Integration”. Wszystkie testy jednostkowe przebiegają w jednym projekcie, a podstawowa struktura kodu źródłowego jest replikowana jako foldery w projekcie. To samo dotyczy testów integracyjnych. Proste rozwiązanie dla projektu może wyglądać następująco:

Solution
   MyProduct.Project1 (Project)
      Folder1 (Folder)
         ClassAA (Class def)
         ...
      Folder2
         ClassAB
         ...
      ClassAC
      ...
   MyProduct.Project2
      Folder1
         ClassBA
         ...
      ClassBB
      ...
   ...
   MyProduct.Tests.Unit
      Project1
         Folder1
            ClassAATests
            ClassAATests2 (possibly a different fixture setup)
         Folder2
            ClassABTests
         ClassACTests
      Project2
         Folder1
            ClassBATests
         ClassBBTests
      ...
   MyProduct.Tests.Integration
      Project1 (a folder named similarly to the project)
         Folder1 (replicate the folders/namespaces for that project beneath)
            ClassAATests
         Folder2
            ClassABTests
         ClassACTests
      Project2
         Folder1
            ClassBATests
         ClassBBTests

W przypadku dowolnych AAT lub AEET, które są zakodowane w ramach testów jednostkowych, zmienia się to nieco; zwykle testy te odzwierciedlają zestaw kroków, które przetestują funkcjonalność nowego przypadku użycia lub historii. Zwykle konstruuję te testy w MyProduct.Tests.Acceptanceprojekcie jako takim, z testami dla każdej historii, ewentualnie pogrupowanymi według kamienia milowego lub „epickiej” historii, do której należała opracowywana historia. Jednak są to tak naprawdę tylko testy integracyjne, więc jeśli wolisz strukturyzować testy w sposób bardziej obiektowy zamiast zorientowany na historię, nie potrzebujesz nawet MyProduct.Tests.Acceptancepodobnego projektu; po prostu wrzuć je w MyProduct.Tests.Integrationzakres testowanego obiektu najwyższego poziomu.

KeithS
źródło
3

Nie ma powodu, aby test jednostkowy był tylko w jednej kategorii. Wszystkie główne zestawy narzędzi do testowania jednostek obsługują tworzenie pakietów testowych , które łączą testy dla określonej kategorii. Po zmianie określonego obszaru kodu programista powinien najpierw uruchomić ten pakiet i często sprawdzać, co się zepsuło. Kiedy test dotyczy wyściółka i przerw i gniazdowania, za wszelką cenę postawić go na wszystkich trzech apartamentach.

Powiedział, że punktem testów jednostkowych jest prowadzony do nich cały czas, to powinny one być małe i wystarczająco szybko, że jest to możliwe, aby uruchomić je wszystkie befor popełnienie jakiegokolwiek kodu. Innymi słowy, tak naprawdę nie ma znaczenia, jaką kategorią jest test, należy go uruchomić przed zatwierdzeniem. Zestawy są tak naprawdę tylko kulą, której używasz, jeśli z jakiegoś powodu nie możesz pisać testów tak szybko, jak powinny.

Jeśli chodzi o zasięg, istnieją bardzo dobre narzędzia pokrycia, które informują o tym, jaki procent linii faktycznie wykonano podczas uruchamiania testów - jest to oczywisty wskaźnik do tego, jakiego rodzaju testów wciąż brakuje.

Jeśli chodzi o nazewnictwo, nie ma szczególnej wartości w nakładaniu wysiłku na nazwy testów jednostkowych. Wszystko, co chcesz usłyszeć z testów, to „5235 z 5235 testów zakończonych pomyślnie”. Gdy test się nie powiedzie, to, co czytasz, nie jest jego nazwą, ale komunikatem , np assert(). Łańcuchem w, który implementuje twój sukces critrion. Wiadomość powinna być wystarczająco informacyjna, abyś miał pojęcie o tym, co jest nie tak, bez przeczytania treści testu. W porównaniu z tym nazwa jest nieważna.

Kilian Foth
źródło
Zgadzam się w 100% na wszystko, co mówisz (nasza maszyna do kompilacji uruchamia wszystkie testy podczas odprawy). Naszym dużym problemem jest śledzenie tego, co testujemy. A pokrycie kodu nie jest zbyt pomocne (patrz aktualizacja powyżej).
David Thielen,
1

Jednym ze sposobów sprawdzenia, czy masz słabość testów, jest identyfikowalność. Zwykle w przypadku testów ma to formę ubezpieczenia.

Celem jest zmierzenie, które części kodu są wykonywane przez twoje testy, abyś mógł zobaczyć kod, który nie jest objęty twoimi testami. To do Ciebie (i narzędzia pokrycia) należy określenie, czym jest „część kodu”. Najmniej jest zasięgiem oddziału.

mouviciel
źródło