Niedawno przeczytałem artykuł, w którym napisano, że fałszywe obiekty są często źle rozumiane i niewłaściwie wykorzystywane. Czy są jakieś szydercze anty-wzory, na które mogę uważać?
Niedawno przeczytałem artykuł, w którym napisano, że fałszywe obiekty są często źle rozumiane i niewłaściwie wykorzystywane. Czy są jakieś szydercze anty-wzory, na które mogę uważać?
Odpowiedzi:
Nienawidzę patrzeć na drwiny z prostych, konkretnych zajęć. Weźmy na przykład następującą prostą klasę, która nie jest zależna od niczego innego:
public class Person
{
private readonly string _firstName;
private readonly string _surname;
public Person(string firstName, string surname)
{
if (String.IsNullOrEmpty(firstName))
{
throw new ArgumentException("Must have first name");
}
if (String.IsNullOrEmpty(surname))
{
throw new ArgumentException("Must have a surname");
}
_firstName = firstName;
_surname = surname;
}
public string Name
{
get
{
return _firstName + " " + _surname;
}
}
}
W każdym teście z tą klasą wolałbym raczej utworzyć prawdziwą i używać jej, zamiast wyciągania jakiegoś interfejsu, takiego jak „IPerson”, używanego kpina i oczekiwania. Używając prawdziwego, twój test jest bardziej realistyczny (masz sprawdzanie parametrów i rzeczywistą implementację właściwości „Nazwa”). W przypadku prostej klasy takiej jak ta nie spowalniasz testów, mniej deterministycznie lub mętniejesz w logice (prawdopodobnie nie będziesz musiał wiedzieć, że nazwa została wywołana podczas testowania innej klasy) - co jest typowym powodem kpin / stubbing
Jako rozszerzenie tego, widziałem również, że ludzie piszą testy, w których próbka jest konfigurowana z oczekiwaniami, a następnie próbka jest wywoływana bezpośrednio w teście. Nic dziwnego, że test zawsze się powiedzie ... hmmmm ...
Może to zabrzmieć oczywisto, ale: Nie używaj fałszywych obiektów w kodzie produkcyjnym! Widziałem więcej niż jeden przykład, w którym kod produkcyjny zależał od właściwości niektórych próbnych obiektów ( MockHttpServletRequest
na przykład z Springframework).
Moim zdaniem jest to nadmierna kontrola wywołania metody na próbach. Wydaje mi się, że jest to praktyka wymuszona przez kilka fałszywych frameworków, takich jak EasyMock, w których domyślnym zachowaniem próbnym jest niepowodzenie za każdym razem, gdy istnieje dodatkowe wywołanie metody, które nie było dokładnie określone wcześniej. Tego rodzaju ścisłe, próbne sprawdzanie metod może prowadzić do kruchych projektów, w których najmniejsza zmiana w kodzie może doprowadzić do niepowodzenia całego zestawu testów, mimo że podstawowa funkcjonalność pozostaje taka sama.
Rozwiązaniem tego problemu jest stosowanie kodów pośredniczących zamiast próbnych. Artykuł szczególnie interesujący na ten temat został znaleziony w Javadoc Mockito: http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html (patrz „2. Co powiesz na stubowanie?”). ), link do: http://monkeyisland.pl/2008/07/12/should-i-worry-about-the-u nieoczekiwany/ .
Do tej pory podobała mi się praca z Mockito, ponieważ nie wymusza to ścisłego kpiącego zachowania, ale zamiast tego stosuje kody pośredniczące. Wymusza także sprawdzanie metod na konkretnych zamiast całego próbnego obiektu; więc kończysz sprawdzanie tylko tych metod, które naprawdę mają znaczenie w twoim scenariuszu testowym.
Jest tu kilka książek i mogę polecić dotknięcie tego tematu, kpiny i ogólne:
Wzory xUnit
Sztuka testowania jednostkowego: z przykładami w .Net
Testy Java nowej generacji: TestNG i zaawansowane koncepcje (ta książka jest głównie o testNG, ale jest ładny rozdział o kpinach)
Answer.RETURNS_SMART_NULLS
ustawienia dla prób, które pomagają to zdiagnozować.
W swoim doświadczeniu zaobserwowałem kilka anty-wzorów.
W przeciwnym razie moje doświadczenia z kpiną, zwłaszcza z Mockito, były proste. Sprawili, że testy są bardzo łatwe do napisania i utrzymania. Testowanie interakcji widok / prezenter GWT jest znacznie łatwiejsze w przypadku próbnych testów niż GWTTestCase.
Uważam, że testy, które wykorzystują próby na wielu warstwach aplikacji, są szczególnie trudne do odczytania i zmiany. Myślę jednak, że zostało to złagodzone w ostatnich latach dzięki ulepszonemu interfejsowi API typu mock framework (używam JMock tam, gdzie jest to wygodne).
5 lub 6 lat temu API takie jak EasyMock były potężne, ale bardzo uciążliwe. Często kod testowy, który go wykorzystywał, był o rząd wielkości bardziej skomplikowany niż kod, który testował. Próbowałem wtedy wpływać na zespoły, z których korzystałem bardzo oszczędnie i radziłem sobie z prostymi ręcznie wykonanymi próbami, które były po prostu alternatywnymi implementacjami interfejsów specjalnie do testowania.
Ostatnio moje mocne opinie na ten temat stały się łagodniejsze, ponieważ szydercze interfejsy API sprawiły, że testy, które wykorzystują je, są bardziej czytelne. Zasadniczo chcę, aby mój kod (w tym testy) mógł być zmieniany przez innych programistów bez powodowania, że czują się, jakby przesiewali przez bagno niejasnych wywołań API.