Test Driven Development: Dobry / zaakceptowany sposób testowania działania systemu plików?

14

W tej chwili pracuję nad projektem, który generuje tabelę (między innymi) na podstawie zawartości systemu plików, a z kolei wprowadza pewne modyfikacje metadanych dotyczących znalezionych elementów. Pytanie brzmi: w jaki sposób należy napisać testy lub skonfigurować? Czy istnieje prosty sposób na wyszydzenie tego? Czy powinienem skonfigurować „piaskownicę”?

Kirbinator
źródło

Odpowiedzi:

13

Jak zawsze w TDD z zasobami zewnętrznymi: tworzysz jeden lub więcej interfejsów do operacji systemu plików i „wyśmiewasz je”. Chcesz przetestować „generator tabel” i kod modyfikacji metadanych, a nie same operacje systemu plików (najprawdopodobniej używasz gotowych implementacji bibliotek do uzyskiwania dostępu do systemu plików).

Doktor Brown
źródło
TDD nie zaleca drwi z implementacji testowanego urządzenia. Zobacz (e, g) solnic.eu/2014/05/22/mocking-and-ruby.html
soru
1
@soru: Nie to zaleca ta odpowiedź. Zaleca się najpierw utworzenie interfejsów, a następnie wyśmiewanie interfejsu . Testujesz logikę biznesową, ale nie interfejs systemu plików.
śleske,
5
Ale wygląda na to, że logika biznesowa jest zdefiniowana w kategoriach plików i katalogów. Rzeczy wywołujące interfejs API systemu plików to rzeczy, które wymagają przetestowania. Testowanie powiązanej logiki biznesowej nieobjętej plikami nie wymaga kpiny; po prostu przetestuj to.
soru,
@soru racja, więc tworzysz cienką warstwę wokół plików i folderów z interfejsem zdefiniowanym tak, że wszystkie operacje specyficzne dla domeny są po stronie klienta, a strona implementacyjna jest na tyle prosta, aby mieć pewność, że działa bez testów jednostkowych (testy integracji nadal będą wymagane). Podobne do idei Humble Dialog w kodzie interfejsu użytkownika lub przy użyciu próbnego repozytorium w kodzie, które działa na obiektach trwałych.
Jules
2
Dlatego skutecznie rezygnujemy z testowania rzeczywistej klasy, która współdziała z systemem plików, bazą danych itp., Zamiast tego tworzymy inną implementację z tym samym interfejsem co próbny / skrótowy, ale rzeczywistą klasę pozostawiamy bez jakiegokolwiek testowania jednostkowego, ponieważ uważamy, że nie możemy go przetestować jednostkowo i zamiast tego powinniśmy przeprowadzić testy integracyjne. Czy to jest poprawne?
Andrew Savinykh
11

Co jest złego w posiadaniu „testowego” systemu plików?

Utwórz szablonową strukturę folderów / katalogów, która ma wystarczającą zawartość do przetestowania operacji.

Podczas konfiguracji testu jednostkowego skopiuj tę początkową strukturę (zaleca się skompresowanie szablonu i rozpakowanie w obszarze testowym). Uruchom swoje testy. Usuń wszystko podczas niszczenia.

Problem z wyśmiewaniem polega na tym, że po pierwsze systemy plików, systemy operacyjne i bazy danych, które należą do twojego projektu, tak naprawdę nie kwalifikują się jako zasoby zewnętrzne, a po drugie, wyśmiewanie wywołań systemowych niskiego poziomu jest zarówno czasochłonne, jak i podatne na błędy.

James Anderson
źródło
5
Wyśmiewanie się z operacji na systemie plików stworzy znacznie (!) Szybsze testy niż przy użyciu prawdziwego systemu plików, a jeśli jest to bardziej podatne na błędy, jest dyskusyjne, powiedziałbym, że zależy to od implementacji. Niemniej jednak myślę, że twoja sugestia jest odpowiednia do tworzenia automatycznych testów integracji (co zwykle robiłbym pierwszy, gdy nie robiłem TDD). Ale OP specjalnie poprosił o TDD, a testy jednostek TDD muszą być szybkie.
Doc Brown,
1
Myślę, że systemy plików, jeśli są wyśmiewane, idealnie powinny mieć cały interfejs API napisany i obsługiwany przez jakąś grupę, ponieważ wymyślasz koło, jeśli robisz coś znaczącego z systemem plików.
Frank Hileman,
2
@Doc Brown - zakładam, że chce wykonywać operacje typu dir, delete i change name, z których wszystkie mają przypadkowe przypadki, których przykrość byłaby bolesna. Również na nowoczesnym sprzęcie rozpakowywanie kilku małych plików do katalogu jest tylko trochę wolniejsze niż ładowanie klasy Java - w końcu to wszystko IO.
James Anderson,
Im więcej myślę o testowym systemie plików, tym bardziej mi się podoba.
Frank Hileman,
3

Jest to coś, czego zdecydowanie potrzebujesz do testu integracji, ponieważ rzeczywiste systemy plików mają wszelkiego rodzaju dziwne zachowania (na przykład sposób, w jaki system Windows nie zezwala na usunięcie pliku, jeśli otwarty jest jakikolwiek proces, w tym program usuwający).

Podejście TDD polega więc na napisaniu najpierw testu integracyjnego (ściśle mówiąc, TDD nie ma odrębnych pojęć „test jednostkowy” i „test integracyjny”; są to tylko testy). Całkiem prawdopodobne, że to wystarczy; więc praca wykonana, przestań, idź do domu .

Jeśli nie, pojawi się pewna złożoność wewnętrzna, która nie jest łatwa do odpowiedniego przetestowania poprzez uporządkowanie plików. W takim przypadku po prostu wyeliminuj tę złożoność, umieść ją w klasie i napisz testy jednostkowe dla tej klasy . Całkiem prawdopodobne, że przekonasz się, że ta wspólna klasa jest użyteczna także w bazach danych, plikach xml itp.

W żadnym wypadku nie wziąłbyś podstawowego rdzenia pisanego kodu i „wyśmiewałeś” go, aby napisać testy, które przejdą, czy testowana jednostka jest błędna.

soru
źródło
Ta odpowiedź naprawdę przedstawia mi perspektywę - 'unit test' and 'integration test'; they are just tests.myślę realistycznie, że będzie to najlepsze rozwiązanie dla mojego przypadku - Naprawdę muszę przetestować biblioteki systemu plików, których używam dla przypadków brzegowych i jak aplikacja powinna na nie zareagować te. Jeśli przejdę do innej biblioteki systemu plików, nie będę musiał przepisywać kilku próbnych / testowych kodów do pracy z nową biblioteką, ale posiadanie struktury folderów testowych i testów integracyjnych ułatwiłoby to.
tehDorf,
2

Rozumiem twoje pytanie jako „Dobry / zaakceptowany sposób przetestowania klasy zależnej od operacji systemu plików”. Nie zakładam, że chcesz przetestować system plików swojego systemu operacyjnego.

Aby utrzymać wysiłek związany z „interfejsami do operacji w systemie plików i„ wyśmiewać je ”, ponieważ sugerowana odpowiedź @Doc Brown jest tak mała, jak to tylko możliwe, dobrym pomysłem jest użycie binarnych strumieni Java lub czytnika tekstu (lub ich odpowiednika w języku c # lub używany język programowania) zamiast używania plików z nazwami plików bezpośrednio w klasie opracowanej przez TDD.

Przykład:

Za pomocą java zaimplementowałem klasę CsvReader

public class CsvReader {
    private Reader reader;

    public CsvReader(Reader reader) {
        this.reader = reader;
    }
}

Do testów wykorzystałem takie dane w pamięci

String contentOfCsv = "TestColumn1;TestColumn2\n"+
    "value1;value2\n";

CsvReader sut = new CsvReader(java.io.StringReader(contentOfCsv));

lub umieść dane testowe w zasobach

CsvReader sut = new CsvReader(getClass().getResourceAsStream("/data.csv"));

W produkcji używam systemu plików

CsvReader sut = new CsvReader(new BufferedReader( new FileReader( "/import/Prices.csv" ) ));

W ten sposób mój CsvReader nie zależy od systemu plików, ale od abstrakcyjnego „Czytnika”, w którym istnieje implementacja systemu plików.

k3b
źródło
2
Jedynym problemem jest to, że OP nie mówił o operacjach na plikach, ale operacjach na systemie plików i operacjach na metadanych - myślę, że miał na myśli coś takiego jak umieszczenie wszystkich plików w katalogu, aktualizacja niektórych informacji EXIF ​​we wszystkich plikach zdjęć itp.
Doc Brown
To jest poprawne.
Kirbinator
1
Możesz utworzyć IDirectoryLister, który ma metodę String [] List (katalog String); następnie FakeDirectoryLister może zaimplementować tę metodę, po prostu zwracając nowy String [] {".", "..", "foo.bat", "bar.exe"};
Anders Lindén,
0

Utwórz opakowanie dla operacji systemu plików. W testach przekaż próbny, który implementuje ten sam interfejs co opakowanie. W produkcji przekaż opakowanie.

jhewlett
źródło