Jak piszesz testy dla kodu, który zależy od konkretnych implementacji zewnętrznych, których nie można wyśmiewać?

17

Tło: Zastanawiam się nad próbą wprowadzenia koncepcji testów jednostkowych do moich współpracowników poprzez stworzenie części dla modułu, nad którym pracowałem; wymagania ostatnio się zmieniły i wymagają kilku dodatkowych abstrakcji / interakcji, więc wydaje się, że to dobry sposób na opracowanie zestawu testów, które „udowodnią”, że działa bez konieczności ręcznego przeszukiwania aplikacji.

Problem polega jednak na tym, że moduł opiera się na niemożliwych do udowodnienia czynnikach zewnętrznych, a mianowicie plikach PDF i XSL. Zasadniczo czytam XML z bazy danych i stosuję do niej transformację XSL, a następnie przekonwertowałem ją na format PDF za pomocą biblioteki o nazwie ABCPDF. Ten plik PDF jest następnie łączony z innym plikiem PDF na podstawie statycznego szablonu. Wiem, że mogę przetestować XML i upewnić się, że wartości są poprawne, ale wiele potencjalnych błędów i problemów związanych jest z faktycznym wyświetlaniem gotowego dokumentu - np. Drobiazgi, takie jak długość zawijanych ciągów tekstowych, gdzie są określone obszary HTML znajduje się w stosunku do dokumentu itp. Czy można nawet przetestować te rzeczy (zdaję sobie sprawę, że są to prawdopodobnie testy integracyjne lub ... trzeci rodzaj testu, którego nazwy zapominam [nie testy akceptacyjne, inny rodzaj], a nie jednostka testy), ponieważ o ile wiem, nie mogę łatwo wykpić pliku PDF bez tworzenia go, a następnie odczytywania go ponownie lub tworzenia ciągu HTML (tj. przekształconego pliku XML) i analizowania go ręcznie w celu sprawdzenia obecności niektórych komórek tabeli w stosunek do innych komórek tabeli.

Czy w takiej sytuacji powinienem po prostu skupić się na testach jednostkowych, aby upewnić się, że informacje są prawidłowe i że mogę utworzyć plik PDF, scalić je, czy cokolwiek innego i skorzystać z ręcznego testowania rzeczywistych problemów z wyświetlaniem?

Wayne Molina
źródło
6
„niepodważalne czynniki zewnętrzne” to wskazówka, że ​​nie przeprowadzasz testów jednostkowych . Oznacza to testy integracyjne . Co chcesz zrobić Jednostka testowanie z Twojego kodu lub testowania integracji tego kompozytu rzeczy? Wybierz jedno lub drugie, ponieważ trudno jest mówić o obu jednocześnie.
S.Lott,
2
Nie kupuję „niemożliwego do wyśmiewania”. Zaakceptuję „że nie umiem kpić”, co oznacza po prostu, że twoje prawdziwe pytanie brzmi „jak kpić?”.
Rein Henrichs,
Prawdopodobnie :) Znam kpiny z używanego XML-a, ale nie wiem, jak kpić z prawdziwego dokumentu PDF lub HTML, jeśli formatowanie ma znaczenie.
Wayne Molina
1
Myślę, że masz na myśli testy „funkcjonalne” (aplikacja od końca do końca) lub „system” (wiele aplikacji od końca do końca)
Gary Rowe
@Gary - Tak, funkcjonalne to było słowo. Teraz pamiętam je z nauki Railsów: modele testów jednostkowych, kontrolery testów funkcjonalnych, integracja testuje wszystko.
Wayne Molina,

Odpowiedzi:

13

Sprawdź funkcję, a nie urządzenie

Korzystając ze znanych danych wejściowych xml, wyślij plik PDF i ręcznie (i dokładnie) sprawdź, czy jest poprawny. Następnie zapisz go jako odniesienie.

Przyszłe testy wykorzystujące te same dane wejściowe xml mogą przeprowadzić porównanie pliku binarnego z odniesieniem.

Jeśli porównanie na poziomie pliku jest niezadowalające, wyświetl plik PDF na końcu testu i zrób zrzuty ekranu, a następnie porównaj automatyczny test z zrzutami ekranu odniesienia.

Steven A. Lowe
źródło
+1, ponieważ interesuje Cię tylko wynik końcowy na tym poziomie. Jeśli zmienisz sposób uzyskiwania pliku PDF, nie musisz zmieniać testu funkcjonalnego.
Gary Rowe,
2
+1 za dobrą radę, oto co robimy w naszym obecnym projekcie. Stworzyliśmy niestandardowy zestaw narzędzi do porównywania plików PDF, który pozwala nam pomijać zmieniające się części w dokumentach, takie jak znaczniki czasu. Zastrzeżenie: przejście na inny (renderujący) moduł renderujący PDF może powodować subtelne zmiany w układzie, powodując bezpośrednie porównanie binarne do stosów sygnałów fałszywie dodatnich.
Péter Török
5

Zwykle w takim przypadku wyodrębnia się wszystko, czego nie można przetestować za implementacją, której można użyć z interfejsem. Zrobię coś głupiego jak narzędzie do tworzenia plików PDF, ponieważ wydaje się to rozsądne.

public class PdfBuilder : IPdfBuilder
{
  public byte[] BuildPdf(...)
  {
    // actual untestable code here
  }
}

public interface IPdfBuilder
{
  byte[] BuildPdf(...);
}

Następnie możesz wyśmiewać IPdfBuilder w testach, aby zrobić co chcesz. Często oznacza to, że musisz zacząć korzystać z kontenera IoC ( /programming/871405/why-do-i-need-an-ioc-container-as-opposed-to-straightforward-di-code i /programming/21288/which-net-dependency-injection-frameworks-are-worth-looking-into jako miejsce na początek), jeśli nie używasz go teraz.

A testy, które nie są testami jednostkowymi, często nazywane są testami integracyjnymi. Skomplikowane testy integracyjne często nie są w pełni tego warte, więc po prostu wyodrębnij tę część i zmniejsz ilość logiki biznesowej w tej abstrakcji, aby można ją było przetestować w teście jednostkowym.

Daj mi znać, jeśli nie jest to całkowicie jasne.

Travis
źródło
+1 za ukrywanie niestabilnego kodu. Następnie możesz wykonywać testy ręczne, dopóki nie zorientujesz się, co należy przekroczyć ten interfejs, aby uzyskać właściwy wynik, oraz test jednostkowy tego wygenerowania poprawnie, aby uzyskać testy jednostkowe regresji.
Ethel Evans,
1

Kiedyś zbudowałem coś bardzo podobnego i po prostu użyłem podstawowych testów wizualnych. Testowanie nie musi być zautomatyzowane, więc nie ma nic złego w szukaniu oczekiwanego rezultatu (oczywiście w różnych sytuacjach, które są z góry określone). Często zdjęcie jest warte tysiąca testów, jeśli chodzi o wizualizacje . Używam zautomatyzowanych testów jednostkowych w szerokim zakresie, ale myślę, że niektórzy ludzie mogą dać się ponieść emocjom podczas wchodzenia w testy GUI lub cokolwiek wizualnego IMHO. W przypadku niektórych produktów zdaję sobie sprawę, że to „wystarczająco dobre” podejście nie będzie wystarczające, więc YMMV.

Byłbym jednak trochę zaniepokojony niemożliwymi do wyśmiewania efektami zewnętrznymi. Może to świadczyć o ścisłym sprzężeniu, którego należy unikać zgodnie z ogólną zasadą, ale nie spekuluję zbytnio na twoim kodzie pod tym względem bez dalszych szczegółów.

Morgan Herlocker
źródło
Jest bardzo ściśle powiązany, ale nie mogę tego naprawić, ponieważ nie ma wpisowego, który sprawi, że będzie luźno powiązany, a refaktoryzacja nie będzie wymagała żadnych zasobów (ale to zupełnie inny zestaw problemów).
Wayne Molina,