2009-09-25 14 views
7

Próbuję postępować zgodnie z dobrymi praktykami podczas pisania moich zestawów testowych. W połowie zdałem sobie sprawę, że wiele wydatków IAM (Most) mojego czasu na fałszywych obiektów ... Większość moich badań robi coś takiegoTestowanie jednostek za pomocą podróbek lub makiet?

public interface ITemplateRepository 
{ 
    string get GetGenericTemplate {get;} 
} 


public FakeTemplateRepository : ITemplateRepository 
{ 
    public string GetGenericTemplate() 
    { 
    return "<xml>Complex</xml>"; 
    } 
} 


[Test] 
public void CanGetGenericTemplate() 
{ 
    ITemplateRepository rep = new FakeTemplateRepository(); 
    Assert.IsNotNull(rep.GetGenericTemplate()); 
} 


[Test] 
public void GetGenericTemplateContains() 
{ 
ITemplateRepository rep = new FakeTemplateRepository(); 
Assert.IsTrue(rep.GetGenericTemplate().StartsWith("<xml>")); 
} 

Rzeczywiście znalazłem się spędzając dużo czasu na FakeTemplateRepository, upewniając się, że zwróciło to rzeczywistą zawartość, której oczekiwałem. Czy to jest złe?

Czy to nadal jest prawidłowy test jednostki? Testy jednostkowe powinny być szybkie i proste, nie? Ale szczerze mówiąc, nie jestem do końca pewny, jedno jest pewne, że moje myśli o kształcie i zawartości moich danych. Zawartość w FakeRepository będzie mniej lub bardziej odzwierciedlać moją zawartość produkcyjną, aczkolwiek odczytywaną z systemu plików, zamiast z pamięci.

Jeśli w rzeczywistości to, co robię, to testy integracyjne, to jak powinienem używać mocków do testów jednostkowych?

To nie ma sensu dla mnie (jeśli korzystam z Mocks), że ustawię oczekiwanie w górę, aby wywołać metodę i zwrócić ciąg znaków? Czy brakuje mi czegoś, ale nie widzę tam zbyt wiele? Kod nawet nie skompiluje się, jeśli ustawię niepoprawną nazwę metody!

Naprawdę jestem bardzo zdezorientowany, a moje postrzeganie testów jednostkowych jest teraz całkowicie rozmyte z tymi wszystkimi koncepcjami.

Czy każdy może wykazać się super super prostym przykładem tego, jak podróbki i makiety pasują do apartamentu? np. Jaki powinien być test jednostkowy, Jaki powinien być test integracyjny?

Dzięki

+0

Cóż, podanie kodu, którego chce, nie będzie zbyt użyteczne, ponieważ testowanie w jego najprostszej formie jest, jak sądzę, "poddaniem go swoim krokom". –

Odpowiedz

9

Po raz kolejny ... inna osoba wpada w próbę Anti-pattern. Wykonujesz "testowanie makiety" lub fałszywego obiektu - który w ogóle nie jest przydatny. Potrzebne są makiety, aby oddzielić zależności lub współpracowników od badanego przedmiotu, a nie sam przedmiot testu.

Po pierwsze, powiedziałbym, przeczytaj artykuł Martina Fowlera "Mocks Aren't Stubs". Jeśli chcesz zwrócić wartości lub skonfigurować oczekiwania dotyczące konkretnych argumentów, przejdź do szyderczego schematu w porównaniu z Roll-your-own fakes. Podróbki są zwykle używane do ukrywania współpracowników ... gdzie nie dbasz o współpracownika .. np. wywołać sieć lub plik IO.
Następne this similar SO question i odpowiedź na niego ..

2

Przede wszystkim nauczyć się izolacja (szyderczy) ramy, jak Moq lub Rhino Mocks. Pozwoli to zaoszczędzić mnóstwo czasu.

Po drugie, unikaj tworzenia makiet, kiedy to możliwe, i trzymaj się stubów. Przedrostki tylko zwracają wartości; nie mówisz przeciwko nim. Zamiast tego twierdzisz, że stan testowanej klasy jest tym, czego oczekiwałeś. Użyj skrótów, aby zablokować wstrzyknięte zależności.

Jest to złożony temat i trzeba trochę popracować.Osherove's Art of Unit Testing jest tani w swojej formie e-booków i całkiem nieźle to tłumaczy. Będziesz także chciał przeczytać na Dependency Injection.

Pamiętaj, że do testowania wielu klas nie potrzebujesz podróbek, mocków ani stubów. Chodzi o to, aby przetestować zachowanie publiczne rzeczywistej klasy w izolacji. Podróbki to po prostu jedno narzędzie, które pomoże ci odizolować klasę od wszelkich zależności.

Twoje przykłady koncentrują się na podróbkach, interfejsach i testach. Skoncentruj się na badanej klasie i jej pożądanym zachowaniu.

Testy integracyjne również mają wartość; możesz wszystko podłączyć do testowej bazy danych i upewnić się, że wszystko działa. Są raczej powolne, w przeciwieństwie do testów jednostkowych.

EDYTOWANIE: Teraz czytam Growing Object-Oriented Software, Guided by Tests i kwestionuję mój punkt widzenia "unikam szydełkowania". Jeśli masz obiekty następujące po Tell, Don't Ask, testowanie stanu może być trudne.

5

W twoim przykładzie testujesz swój podróbek. Nie można tego zrozumieć, bo to nie ma sensu.

Oto przykład, w jaki sposób powinieneś używać podróbek. Chcesz przetestować jednostkę klasy DocumentGenerator. Ta klasa korzysta z usług ITemplateRepository. Jednakże, aby prawidłowo testować DocumentGenerator, należy upewnić się, że nie zależy to od usług zewnętrznych. Dostarczasz DocumentGenerator fałszywego ITemplateRepository, który zwróci wyniki w puszkach.

Oto, jak wygląda kod.

public class DocumentGenerator 
{ 
    ITemplateRepository _repo; 

    DocumentGenerator(ITemplateRepository repo) 
    { 
    _repo = repo; 
    } 

    Doc GenerateDoc() 
    { 
    .... 
    _repo.GetGenericTemplate(); 
    .... 
    } 
} 


[Test] 
public void GenerateDocTest() 
{ 
    ITemplateRepository rep = new FakeTemplateRepository(); 
    DocumentGenerator docGenerator = new DocumentGenerator(rep); 
    Assert.IsNotNull(docGenerator.GenerateDoc()); 
} 

Istotą przykładzie jest to, że testowanie coś, co wykorzystuje fałszywy. Nie testujesz samego fałszywego. Fałsz istnieje, więc to, co testujesz, nie zależy od czegoś zewnętrznego.

+0

Co się stanie, jeśli DocumentGenartor nie akceptuje repozytorium, ale zamiast tego wartość łańcucha czegoś, co jest zwracane z repozytorium? to znaczy.DocumentGenerator (szablon ciągów znaków). Jeśli musiałbym zrobić coś takiego, to czy sugeruje, że mam zły projekt? –

+0

Jeśli DocumentGenartor pobiera tylko String, w ogóle nie potrzebujesz fałszywego obiektu. Trzeba tylko tworzyć fałszywe obiekty dla współpracowników, których faktycznie używa jednostka testowana. –

Powiązane problemy