Jeżeli testy jednostkowe obejmują wyłącznie oprogramowanie „funkcjonalne”

9

Używamy StructureMap w nowym projekcie rozwoju oprogramowania. Jeden z członków zespołu wdrożył test jednostkowy, który zasadniczo testuje konfigurację kontenera StructureMap . Robi to, wykonując następujące czynności;

  • Liczy liczbę wystąpień zestawów skonfigurowanych dla klas w naszej przestrzeni nazw aplikacji.
  • Definiuje oczekiwane wystąpienia na poziomie klasy
  • Zapewnia, że ​​oczekiwane wystąpienia są zgodne z całkowitą liczbą znalezionych wystąpień.
  • Zapewnia, że ​​oczekiwane wystąpienia są zgodne z tymi zdefiniowanymi w teście

Przykładem tego jest;

var repositories = container.GetAllInstances<IEnvironmentRepository>();
Assert.AreEqual(1, repositories .Count());
foundInstances = foundInstances + repositories .Count();

Mamy również „testy jednostkowe” dla następującej klasy;

public MyClass(IEnvironmentRepository environmentRepository)
        {

        }

W tych testach wyśmiewamy IEnvironmentRepository, więc nie wstrzykiwalibyśmy go z kontenera, jak to by się stało w systemie na żywo.

Kolega zignorował test jednostkowy w konfiguracji mapy struktury z komentarzem w stylu „Test jednostkowy testuje tylko własną konfigurację”. To był oczywiście cel testu i moim zdaniem jest całkowicie poprawny. Poprosiłem faceta, który zignorował test, o usunięcie konfiguracji mapy struktury dla IEnvironmentRepository(z testem wciąż ignorowanym) i uruchomienie pełnego zestawu testów jednostkowych, wszystkie przeszły pomyślnie. Następnie uruchomiliśmy aplikację, która się przewróciła, ponieważ konfiguracja kontenera była teraz nieprawidłowa. Moim zdaniem potwierdziło to wartość testu, mój kolega wciąż się nie zgadzał. Po prostu stwierdził, że nie powinniśmy testować konfiguracji, ale uważam, że mieści się to w zakresie testów jednostkowych.

Tak więc szereg pytań;

  • Czy to prawidłowy test jednostkowy - Testujemy konfigurację naszego kontenera, nie działa mapa struktury (ale widzę nakładanie się)
  • Jeśli nie, w jaki sposób można sprawdzić poprawność konfiguracji bez jej testowania. Jak powstrzymać kogoś przed przypadkowym usunięciem wymaganego wiersza kodu i wpisaniem go?
  • Czy MyClasstest jednostkowy powinien rozwiązać instancję IEnvironmentRepositoryz kontenera i przekazać ją?
ChrisBint
źródło
10
9 na 10 nieporozumień dotyczących testów wynika z faktu, że frameworki obsługują automatyczne testy we wszystkich ich postaciach, a ludzie chcą uzyskać semantykę, czy dany automatyczny test jest dobrym i właściwym testem jednostkowym, czy nie. Test, który opisujesz, brzmi jak rodzaj niezupełnie testu jednostkowego, który może być bardzo przydatny w automatyzacji (i uruchamianiu podczas sprawdzania) - po prostu nie nazywaj go testem jednostkowym. Zapytaj, czy twój kolega lepiej spałby w nocy, gdyby test żył we własnej funkcji / folderze, który był wyraźnie oddzielony.
Jeroen Mostert
2
To też moim zdaniem, prawdopodobnie przydatne, i choć nie jest to ściśle test jednostkowy, ma wartość dodaną i zostało to udowodnione. Jego odpowiedź brzmiała, że ​​inne testy jednostkowe wykryłyby to, ale moim zdaniem, gdyby zostały napisane jako ścisłe testy jednostkowe, wyśmiewalibyście się zależności i dlatego nigdy nie wiedzielibyście, czy konfiguracja jest poprawna, dopóki jej nie użyjecie.
ChrisBint,
4
Twój kolega ma rację, gdy mówi, aby nie testować konfiguracji, ponieważ oryginalna konfiguracja, która może się różnić w zależności od wdrożenia, nie może / nie powinna być testowana - kto powie, że „czerwony” jest niewłaściwy, a „niebieski” nie? Test byłby ściśle powiązany z jednym zestawem. Ale konfiguracja powiązana z artefaktami kodu jest trochę wyjątkiem, ponieważ nie zmienia się i istnieją wyraźne sposoby, aby go pomylić. Idealnie byłoby, gdyby taka konfiguracja była generowana w czasie kompilacji z SUCHYCH metadanych, ale tam, gdzie nie jest to wykonalne, taki test dodaje wartości. To lepsze niż błąd wdrożenia, którego można uniknąć.
Jeroen Mostert
2
To, co opisujesz, nie testuje urządzenia, testuje konfigurację oprogramowania innej firmy. Fantastycznie przydatne są testy, które testują te rzeczy, ale są to testy integracyjne, a nie testy jednostkowe, a rozłączenie może być przyczyną niezgody.
Phoshi
3
@ChrisBint Dobroć łaskawy nie, sam napisałem kilka testów kontenerów. Mają dużą wartość, po prostu nie są testami jednostkowymi. W porządku, testy integracyjne są niezwykle cenne do łapania rzeczy, których testy jednostkowe nie mogą .
Phoshi,

Odpowiedzi:

13

Jest to doskonale ważny automatyczny test. Nazywam je „testami architektury”, ponieważ weryfikują one poprawność szkieletowych elementów bazy kodu.

Czy kontener IoC jest w stanie rozpoznać i skomponować wszystkie drzewa obiektów w aplikacji? Czy auto Mapper może bezbłędnie mapować wszystkie zarejestrowane obiekty? Czy środkowa warstwa w Architekturze Cebuli nie odwołuje się do niczego zewnętrznego?

Testy te mogą zaoszczędzić dużo czasu, gdy pojawia się błąd konfiguracji, wskazując dokładnego winowajcę. Dobre frameworki dostarczają bardzo precyzyjnych komunikatów o błędach dotyczących tego, co jest nie tak, i otrzymujesz je, gdy tylko uruchomisz testy (najlepiej w sposób ciągły), a nie zakopujesz głęboko ślad stosu wykonawczego, jeśli masz szczęście.

Niezależnie od tego, czy są to testy jednostkowe ... prawdopodobnie nie, ale nadal działają w większości w pamięci i działają dość szybko. Z drugiej strony, nie wiem, to nie jest tak, że istniała powszechnie akceptowana definicja testu jednostkowego.

guillaume31
źródło
Jak na ironię, tak właśnie wyjaśniłem mojemu koledze, a nawet podczas sprawdzania poprawności (usuń jedną z instancji kontenera i uruchom aplikację) nadal nie widział żadnej wartości. Rozumiem, że każdy ma swoje zdanie i wyraziłem swoje;) Uwielbiam termin „test architektury”, zamierzam go ukraść!
ChrisBint,
6

Problem z takim testem, który testuje wewnętrzne elementy programu, a nie jego wymaganie. Czy test może się nie powieść, nawet jeśli program działa zgodnie z wymaganiami.

W twoim przypadku, za każdym razem, gdy zmieniasz konfigurację kontenera, być może masz nową zależność, która wymaga wstrzyknięcia, przerywasz test.

Dodatkowo, jeśli dodasz dodatkowy wymóg zależności, ale zapomnij dodać go do kontenera i zmienić test kontenera. wszystko minie, ale twój program się zawiesi.

Lepszym automatycznym testem byłoby uruchomienie programu i sprawdzenie, czy ulega awarii.

Tego typu błędy należy wychwycić podczas testów integracji lub interfejsu użytkownika, nawet jeśli przejdą one testy jednostkowe.

To powiedziawszy, rosnąca złożoność konfiguracji kontenera jest uciążliwa. Być może niektóre „złe” testy są tego warte.

Ewan
źródło
1

Kod testu jednostkowego. Wszystko poza tym to „inne” automatyczne testy - nazwij to jak chcesz. Wygląda na to, że testujesz tutaj konfigurację. Jeśli konfiguracja może ulec zmianie w zależności od środowiska, nie należy do testu jednostkowego. Rozważ dodanie atrybutu testu, aby wskazać, że test jest innego typu niż inne testy.

Robbie Dee
źródło
Konfiguracja jest statyczna, nie jest sterowana przez środowisko, wszystkie klasy, które istnieją w konfiguracji, będą używane we wszystkich środowiskach w ten sam sposób. Tak, liczba instancji, które mogą być w konfiguracji, powinna odpowiadać liczbie instancji w konfiguracji, która jest częścią testu. Jak pokazał mój przykład, usunięcie IEnvironmentRepository pozwoliło na przejście innych testów jednostkowych. Konkretny test pojemnika nie powiódłby się na 2 Asserts; 1 - Łączna liczba możliwych deklaracji instancji nie jest zgodna, a 2 - konkretna liczba instancji IEnvironmentRepository nie pasowałaby.
ChrisBint,
1
Prawidłowość kontenera określa koder. Fakt, że zarówno testowany kod, jak i sam test muszą się zmieniać dla każdej modyfikacji, natychmiast powoduje dzwonienie dzwonków alarmowych. DI jest środkiem do celu, a nie celem samym w sobie. Zupełnie możliwe jest pisanie kodu w stylu DI bez mapy struktury ergo, więc moim zdaniem nie jest to test jednostki bona fide. Kontener oczywiście musi zostać udowodniony, ale skuteczność przeprowadzania go za pomocą testów automatycznych wydaje się nieco dyskusyjna, z ograniczoną ilością informacji tutaj podanych.
Robbie Dee,
2
Testy jednostkowe zajęły 10 minut. Wdrożenie może potrwać ponad godzinę.
ChrisBint,
1
Biorąc pod uwagę część testu jednostkowego, konkretnie potwierdza istnienie pojedynczej linii w konfiguracji, nie jestem pewien, jak to nie mogło być bardziej izolowane. Ogólna liczba, z którą mógłbym się zgodzić.
ChrisBint,
1
Może wtedy być w nich jakiś przebieg - tak naprawdę wezwanie do sądu. Ale należy je oddzielić fizycznie lub za pomocą jakiegoś atrybutu.
Robbie Dee,
0

Pojemnik do wstrzykiwania zależności jest odpowiedzialny za przyklejenie różnych modułów w jednej działającej aplikacji .

Jeśli piszesz automatyczne testy dla swojej aplikacji - powinieneś mieć niewiele testów integracyjnych (lub akceptacyjnych), które wykonują testy „od końca do końca”, które przetestują cały potok aplikacji, że wszystkie moduły związane z konkretnym przypadkiem testowym są ze sobą sklejone poprawnie .

Te testy integracji zakończą się niepowodzeniem, jeśli kontener wstrzykiwania zależności nie zostanie poprawnie skonfigurowany. Co sprawia, że ​​testy jednostkowe dla samego kontenera są bezużyteczne, ponieważ test integracyjny powinien pokazać możliwe błędy w konfiguracji kontenera.

Nie musisz uwzględniać wszystkich możliwych przypadków testowych w testach integracyjnych, tylko jeden przypadek testowy na funkcję, który obejmuje całą drogę od interfejsu użytkownika do bazy danych.

Jeśli przypadki testowe integracji nie obejmują tworzenia określonej zależności, wystarczy ją dodać.

Dzięki testom integracyjnym możesz dowolnie zmieniać kontenery bez przepisywania testów jednostkowych w celu ich konfiguracji.

Fabio
źródło
0

IMO, odpowiedzi są następujące:

  1. Czy to prawidłowy test jednostkowy - Testujemy konfigurację naszego kontenera, nie działa mapa struktury (ale widzę nakładanie się)

    • Jest to poprawny test jednostkowy dla mapy struktury , nie dla twojego projektu, ponieważ test jednostkowy testuje określony kod, kpiąc ze wszystkich zależności, jeśli to konieczne, w celu przetestowania zaimplementowanej logiki. Logika konfiguracji jest zaimplementowana wewnątrz mapy struktury, dlatego ta biblioteka musi być dobrze przetestowana i musi zawierać testy jednostkowe, takie jak ta, o której wspomniałeś, i jeszcze więcej: powinna zawierać setki takich testów, dynamicznie wyśmiewać kilka konfiguracji w czasie wykonywania i testować, aby sprawdzić, czy pojemnik zachowuje się tak, jak powinien.
  2. Jeśli nie, w jaki sposób można sprawdzić poprawność konfiguracji bez jej testowania. Jak powstrzymać kogoś przed przypadkowym usunięciem wymaganego wiersza kodu i wpisaniem go?

    • Możesz przetestować konfigurację ręcznie w wymaganym środowisku, a także możesz utworzyć automatyzację dla tego (test automatyczny), który testuje konkretną konfigurację, której potrzebujesz (nie musisz wyśmiewać rzeczy w czasie wykonywania).
  3. Czy test jednostkowy MyClass powinien rozwiązać instancję IEnvironmentRepository z kontenera i przekazać ją do?

    • Nie, jest to idealny test jednostkowy, ponieważ wyśmiewasz zależność i testujesz logikę MyClass w izolowany sposób.
Emerson Cardoso
źródło
-1

UnitTest weryfikuje pożądane zachowanie jednostki w separacji .

Oznacza to, że każdy rodzaj konfiguracji jest nie w zakresie UnitTests .

Niemniej jednak powinieneś mieć zautomatyzowane testy dla swoich konfiguracji, ale to nie są testy UnitTest ...

Timothy Truckle
źródło
Skąd czerpiesz definicję jednostek?
ChrisBint,
Podoba mi się ten, który napisał Roy Osherove w The Art Of Unittesting : Unit to każdy fragment kodu (produkcyjnego), który ma ten sam powód do zmiany. W moim świecie zwykle waha się od jednej klasy do trzech lub pięciu ...
Timothy Truckle
To jest testowany kod produkcyjny.
ChrisBint,
Chciałem tylko odwrócić uwagę nitpickerów , nie spodziewając się, że to też działa na odwrót ...; o)
Timothy Truckle