Najlepsze praktyki nazywania testów jednostkowych [zamknięte]

564

Jakie są najlepsze praktyki nazywania klas testów jednostkowych i metod testowania?

Zostało to omówione wcześniej w SO, w Jakie są popularne konwencje nazewnictwa dla testów jednostkowych?

Nie wiem, czy to jest to bardzo dobre podejście, ale obecnie w moich projektów testowych, mam jeden do jednego mapowania między każdej klasie produkcji i klasy testowej, np Producta ProductTest.

W moich klasach testowych mam następnie metody z nazwami metod, które testuję, podkreślenie, a następnie sytuację i to, czego się spodziewam, np Save_ShouldThrowExceptionWithNullName().

James Newton-King
źródło
Zobacz tutaj: stackoverflow.com/questions/96297/…
Forgotten Semicolon
1
To nie odpowiada na twoje pytanie, ale warto przeczytać: haacked.com/archive/2012/01/02/structures-unit-tests.aspx
Robs
3
Przewodnik po stylu Google mówi: test<MethodUnderTest>_<state>np. testPop_emptyStack Google-styleguide.googlecode.com/svn/trunk/javaguide.html 5.2.3 Nazwy metod. W razie wątpliwości śledź Google.
Ciro Santilli 28 冠状 病 六四 事件 法轮功
2
@CiroSantilli 六四 事件 法轮功 包 卓 轩 Następne zdanie mówi: „Nie ma jednego poprawnego sposobu nazwania metod testowych”. Domyśl.
user2418306
1
Nadal wolę zalecenie Phila Haacka nawet po latach.
pimbrouwers,

Odpowiedzi:

524

Podoba mi się strategia nazywania Roya Osherove'a :

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Zawiera wszystkie potrzebne informacje na temat nazwy metody w uporządkowany sposób.

Jednostka pracy może być tak mała jak pojedyncza metoda, klasa lub tak duża jak wiele klas. Powinien reprezentować wszystkie rzeczy, które mają być testowane w tym przypadku testowym i są pod kontrolą.

W przypadku zestawów używam typowego .Testszakończenia, które moim zdaniem jest dość powszechne i takie samo dla klas (kończących się na Tests):

[NameOfTheClassUnderTestTests]

Wcześniej używałem Urządzenia jako sufiksu zamiast Testów, ale myślę, że ten drugi jest bardziej powszechny, potem zmieniłem strategię nazewnictwa.

Marc Climent
źródło
228
Dla mnie nie ma sensu umieszczać nazwy metody w metodzie testowej. Co jeśli zmienisz nazwę metody? Żadne narzędzie do refaktoryzacji nie zmieni nazwy testów dla Ciebie. Ostatecznie zmieniasz nazwy metod testowych ręcznie lub, co bardziej prawdopodobne, na błędnie nazwane testy. To jak z komentarzami. Jest o wiele gorzej niż w ogóle nie komentowanie kodu.
Piotr Perak
80
@Peri, myślę, że to kompromis. Z jednej strony nazwy testów mogą stać się nieaktualne, z drugiej strony nie możesz powiedzieć, jaką metodą testujesz test. Uważam, że ten drugi pojawia się znacznie częściej.
Joel McBeth,
15
Aby dodać do komentarza Peri - wszystkie metody są odpowiedzialne za pewne działania, np UpdateManager.Update(). Mając to na uwadze, zwykle nazywam swoje testy WhenUpdating_State_Behaviourlub WhenUpdating_Behaviour_State. W ten sposób testuję określoną akcję klasy, unikając umieszczenia nazwy metody w nazwie testowej. Ale najważniejsze jest to, że muszę mieć pojęcie, jaka logika biznesowa zawodzi, gdy widzę nazwę testu zakończonego niepowodzeniem
Ramunas,
8
Resharper i IntelliJ prawdopodobnie znajdą metodę testową i zaoferują zmianę jej nazwy, jeśli zmienisz jej nazwę / zmienisz nazwę za pomocą tych narzędzi. Staraj się także szukać w komentarzach, w których wspominasz nazwę metody, i aktualizuj je.
Jeff Martin,
62
Dobre nazwy metod często są takie same, jak działanie, które wykonuje metoda. Jeśli musisz zdecydować między nazwaniem testu po metodzie, a akcją, którą wykonuje metoda , może to być wskazówka, że ​​powinieneś zmienić nazwę metody . (Jednak nie w każdym przypadku)
Kaadzia,
121

Lubię stosować się do standardu nazewnictwa „Powinien” dla testów podczas nazywania urządzenia testowego po testowanym urządzeniu (tj. Klasie).

Aby zilustrować (używając C # i NUnit):

[TestFixture]
public class BankAccountTests
{
  [Test]
  public void Should_Increase_Balance_When_Deposit_Is_Made()
  {
     var bankAccount = new BankAccount();
     bankAccount.Deposit(100);
     Assert.That(bankAccount.Balance, Is.EqualTo(100));
  }
}

Dlaczego „powinien” ?

Uważam, że zmusza to autorów testów do nazwania testu zdaniem: „Powinno [być w jakimś stanie] [za / przed / kiedy] [akcja ma miejsce]”

Tak, pisanie „Powinieneś” wszędzie robi się trochę powtarzalne, ale jak powiedziałem, zmusza pisarzy do myślenia we właściwy sposób (może to być dobre dla nowicjuszy). Dodatkowo generalnie daje czytelną angielską nazwę testu.

Aktualizacja :

Zauważyłem, że Jimmy Bogard jest także fanem „powinien”, a nawet ma bibliotekę testów jednostkowych o nazwie Powinien .

Aktualizacja (4 lata później ...)

Dla zainteresowanych moje podejście do testów nazewniczych ewoluowało przez lata. Jeden z problemów ze wzorem „ Powinienem” opisać powyżej, ponieważ nie jest łatwo na pierwszy rzut oka stwierdzić, która metoda jest testowana. W przypadku OOP myślę, że bardziej sensowne jest rozpoczęcie nazwy testu od testowanej metody. W przypadku dobrze zaprojektowanej klasy powinno to skutkować czytelnymi nazwami metod testowych. Teraz używam formatu podobnego do <method>_Should<expected>_When<condition>. Oczywiście w zależności od kontekstu możesz zamienić czasowniki Powinien / Kiedy na coś bardziej odpowiedniego. Przykład: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()

Jack Ukleja
źródło
32
Może nawet lepiej i mniej zbędne, wystarczy napisać zdanie, które mówi, co robi, zakładając prac badawczych: increasesBalanceWhenDepositIsMade().
hotshot309,
3
Ostatnio widziałem artykuł, w którym wspomniano o podobnej konwencji nazewnictwa (chciałbym ją dodać do zakładek). Zaprojektowany, aby listy testów były bardzo czytelne, gdy zostały posortowane według urządzeń testowych. Zobaczysz coś w rodzaju „BankAccount”, a następnie pod nim (w różnych wierszach) „Should_Increase_Balance_When_Deposit_Is_Made” „Should_Decrease_Balance_When_Withdrawal_Is_Made” itp. Czyta się bardzo podobnie do specyfikacji, na której tak naprawdę polega TDD.
Simon Tewsi
Znaleziono artykuł. Jest na blogu CodeThinked Justina Etheredge'a Rozpoczęcie drwiny z Moq 3 - część 1 .
Simon Tewsi
11
Używam również „Powinien i kiedy”, ale na odwrót. np. WhenCustomerDoesNotExist_ShouldThrowException (). Dla mnie ma to o wiele większy sens niż powinien wtedy (kiedy w pewnym scenariuszu powinien być określony oczekiwany wynik). To również pasuje do AAA (Arrange, Act, Assert) ... Assert jest na końcu ... nie na początku ;-)
bytedev
2
@ Schneider: biorąc pod uwagę „powinien” = „zalecany”, a następnie opcjonalny, zastanawiam się: czy nie byłoby lepiej leksykalnie używać „powinien” = „trzeba”, a następnie wymagane / obowiązkowe. Na przykład RFC odróżniają oba. Więc posiadanie testów jest zalecane czy wymagane?
blackwizard
79

Podoba mi się ten styl nazewnictwa:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

i tak dalej. Dla osoby niebędącej testerem naprawdę wyjaśnia, na czym polega problem.

Sklivvz
źródło
63
ale @ hotshot309 może używać .NET - Konwencje
Ace
2
@ Ace, całkowicie się z tobą zgadzam i zauważyłem to około minuty po opublikowaniu tego komentarza. Przysięgałem, że usunąłem go, gdy zobaczyłem swój błąd, ale jakoś chyba nie. Przepraszam za to.
hotshot309
3
@CoffeeAddict, ponieważ podkreślenia w identyfikatorach to <del> aberracja </del> niezbyt idiomatyczna w C #
Sklivvz
2
Lubię też unikać używania shouldWolę willtakOrdersWithNoProductsWillFail()
Calin
4
@Calin Moim zdaniem używanie Willnie jest właściwie właściwe, a tym samym błędnie mówisz czytelnikowi, że w żaden sposób test nie powiedzie się ... jeśli użyjesz Willwyrażenia czegoś w przyszłości, co może się nie zdarzyć, jesteś niewłaściwe użycie, ale Shouldjest to lepszy wybór, ponieważ wskazuje, że chcesz / chcesz, aby coś się wydarzyło, ale nie zrobiło to lub nie mogło, po uruchomieniu testu informuje, czy nie powiodło się / powiodło, więc nie możesz tego sugerować wcześniej jest to logiczne wytłumaczenie, jakie jest twoje? Dlaczego unikasz Should?
Eyal Solnik,
51

Kent Beck sugeruje:

  • Jedno urządzenie testowe na „jednostkę” (klasa twojego programu). Urządzenia testowe to same klasy. Nazwa urządzenia testowego powinna brzmieć:

    [name of your 'unit']Tests
    
  • Przypadki testowe (metody urządzeń testowych) mają nazwy takie jak:

    test[feature being tested]
    

Na przykład mając następującą klasę:

class Person {
    int calculateAge() { ... }

    // other methods and properties
}

Urządzeniem testowym byłoby:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}
Sergio Acosta
źródło
4
Chciałbym, aby więcej osób przestrzegało tych wytycznych. Nie tak dawno temu musiałem zmienić nazwę ponad 20 metod testowych, ponieważ miały one nazwy takie jak „ATest”, „BasicTest” lub „ErrorTest”.
Wedge
85
czy prefiks metody „test” nie staje się zbędny, biorąc pod uwagę przyrostek klasy?
Gavin Miller
50
Pamiętaj, że kiedy Kent napisał tę książkę. Atrybuty nie zostały wymyślone. Dlatego nazwa Test w nazwie metody wskazywała na środowisko testowe, że metoda była testem. Również wiele się wydarzyło od 2002 roku.
Thomas Jespersen
14
testCalculateAge ... to bez znaczenia nazwa twojej metody testowej. „test” jest zbędny (czy nazywasz wszystkie swoje metody prefiksem „metoda”?). Reszta nazwy nie ma warunków do testowania ani tego, czego oczekiwano. Czy metoda CalculateAge jest testowana? ..... kto wie ...
bytedev
1
Chciałbym dodać, że podczas korzystania z tej strategii wymagana jest dokumentacja w celu określenia oczekiwanego wyniku. Na marginesie na temat przedrostka „test”; niektóre ramy testów jednostkowych wymagają określonych prefiksów lub sufiksów, aby rozpoznać testy. Prefiksowanie klas abstrakcyjnych za pomocą „Abstrakcyjnego” nie jest uważane za zbędne (ponieważ jest to samo dokumentowanie), więc dlaczego to samo nie dotyczy „Test”?
siebz0r
17

Nazwy klas . W przypadku nazw urządzeń testowych uważam, że „Test” jest dość powszechny w wszechobecnym języku wielu domen. Na przykład, w dziedzinie inżynierii: StressTesti w domenie kosmetyki: SkinTest. Przykro mi, że nie zgadzam się z Kentem, ale użycie „Test” w moich urządzeniach testowych ( StressTestTest?) Jest mylące.

„Jednostka” jest również często używana w domenach. Np MeasurementUnit. Czy klasa nazywana MeasurementUnitTestjest testem „Measurement” lub „MeasurementUnit”?

Dlatego lubię używać przedrostka „Qa” dla wszystkich moich klas testowych. Np QaSkinTesta QaMeasurementUnit. Nigdy nie jest mylony z obiektami domeny, a użycie przedrostka zamiast przyrostka oznacza, że ​​wszystkie urządzenia testowe żyją razem wizualnie (przydatne, jeśli w projekcie testowym masz podróbki lub inne klasy wsparcia)

Przestrzenie nazw . Pracuję w C # i utrzymuję moje klasy testowe w tej samej przestrzeni nazw co klasa, którą testują. Jest to wygodniejsze niż posiadanie osobnych testowych przestrzeni nazw. Oczywiście klasy testowe są w innym projekcie.

Nazwy metod testowych . Lubię nazywać moje metody WhenXXX_ExpectYYY. Wyjaśnia to warunek wstępny i pomaga w zautomatyzowanej dokumentacji (a la TestDox). Jest to podobne do porady na blogu testowym Google, ale z większą separacją warunków wstępnych i oczekiwań. Na przykład:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory
Grundoon
źródło
mówiłeś o nazwach metod testowych i nazwach urządzeń testowych. nazwy urządzeń testowych są mapowane na klasy produkcyjne. gdzie piszesz nazwę metody produkcji w teście?
Światło
12

Używam koncepcji Given-When-Then . Spójrz na ten krótki artykuł http://cakebaker.42dh.com/2009/05/28/given-when-then/ . Artykuł opisuje tę koncepcję w kategoriach BDD, ale można jej również używać w TDD bez żadnych zmian.

Pashec
źródło
Biorąc pod uwagę, kiedy-to jest to samo, co MethodName_Scenario_ExpectedBehavior, prawda ?!
Światło
1
Nie dokładnie. Given_When_Then odnosi się bardziej do: GivenAnEntity_WhenSomeActionHappens_ThatResultIsExpected Test powinien wyrażać wolę przetestowania zachowania, a nie implementacji .
plog17
1
„Given When When” jest często nazywane korniszonem. Jest to DSL, który wyszedł z narzędzi Cucumber, JBehave i Behat.
bytedev
+1 to najlepsza metoda imo. Oddzielenie, w jaki sposób metoda robi coś od tego, czego oczekuje się od wyniku, jest bardzo potężne i pozwala uniknąć wielu problemów opisanych w innych komentarzach.
Lee
7

Myślę, że jedną z najważniejszych rzeczy jest zachowanie spójności w konwencji nazewnictwa (i uzgodnienie tego z innymi członkami twojego zespołu). Wiele razy widzę mnóstwo różnych konwencji używanych w tym samym projekcie.

bytedev
źródło
7

Niedawno opracowałem następującą konwencję nazywania moich testów, ich klas i zawierających projekty w celu maksymalizacji ich opisów:

Powiedzmy, że testuję Settingsklasę w projekcie w MyApp.Serializationprzestrzeni nazw.

Najpierw utworzę projekt testowy z MyApp.Serialization.Testsprzestrzenią nazw.

W ramach tego projektu i oczywiście przestrzeni nazw utworzę klasę o nazwie IfSettings(zapisaną jako IfSettings.cs ).

Powiedzmy, że testuję tę SaveStrings()metodę. -> Wymienię test CanSaveStrings().

Po uruchomieniu tego testu wyświetli się następujący nagłówek:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Myślę, że to mówi mi bardzo dobrze, co testuje.

Oczywiście użyteczne jest to, że w języku angielskim rzeczownik „Testy” jest taki sam, jak czasownik „testy”.

Nazewnictwo testów nie ma ograniczeń co do kreatywności, dzięki czemu otrzymujemy pełne nagłówki zdań.

Zwykle nazwy testów będą musiały zaczynać się od czasownika.

Przykłady obejmują:

  • Wykrywa (np. DetectsInvalidUserInput)
  • Rzuty (np. ThrowsOnNotFound)
  • Will (np. WillCloseTheDatabaseAfterTheTransaction)

itp.

Inną opcją jest użycie „tego” zamiast „jeśli”.

Ten ostatni oszczędza mi jednak naciśnięć klawiszy i dokładniej opisuje to, co robię, ponieważ nie wiem, czy testowane zachowanie jest obecne, ale testuję, czy tak jest.

[ Edytuj ]

Po dłuższym użyciu powyższej konwencji nazewnictwa odkryłem, że prefiks If może być mylący podczas pracy z interfejsami. Tak się składa, że ​​klasa testowa IfSerializer.cs wygląda bardzo podobnie do interfejsu ISerializer.cs na karcie „Otwórz pliki”. Może to być bardzo denerwujące przy przełączaniu między testami, testowaną klasą i jej interfejsem. W rezultacie chciałbym teraz wybrać to na razie jako przedrostek.

Dodatkowo teraz używam - tylko dla metod w moich klasach testowych, ponieważ nigdzie indziej nie jest to uważane za najlepszą praktykę - „_” do oddzielania słów w nazwach metod testowych jak w:

[Test] public void detects_invalid_User_Input()

Uważam to za łatwiejsze do odczytania.

[ Zakończ edycję ]

Mam nadzieję, że zrodziło to kilka pomysłów, ponieważ uważam, że testy nazewnicze mają ogromne znaczenie, ponieważ mogą zaoszczędzić dużo czasu, który w innym przypadku poświęciłby na zrozumienie, co robią testy (np. Po wznowieniu projektu po dłuższej przerwie) .

Thorsten Lorenz
źródło
2

W VS + NUnit zwykle tworzę foldery w moim projekcie, aby grupować testy funkcjonalne razem. Następnie tworzę klasy urządzeń do testów jednostkowych i nazywam je na podstawie rodzaju testowanej funkcjonalności. Metody [Test] mają nazwy Can_add_user_to_domain:

- MyUnitTestProject   
  + FTPServerTests <- Folder
   + UserManagerTests <- Test Fixture Class
     - Can_add_user_to_domain  <- Test methods
     - Can_delete_user_from_domain
     - Can_reset_password
Kev
źródło
2

Powinienem dodać, że utrzymywanie testów w tym samym pakiecie, ale w równoległym katalogu do testowanego źródła, eliminuje wzdęcie kodu, gdy tylko będziesz gotowy go wdrożyć bez konieczności wykonywania szeregu wzorców wykluczania.

Osobiście lubię najlepsze praktyki opisane w „JUnit Pocket Guide” ... trudno jest pokonać książkę napisaną przez współautora JUnit!

Steve Moyer
źródło
3
Nie sądzę, że to faktycznie odpowiada na pytanie - czy możesz dokonać edycji i odwołać się do JUnit Pocket Guide? Dzięki!
Nate-Wilkins
0

nazwa przypadku testowego dla klasy Foo powinna być FooTestCase lub coś podobnego (FooIntegrationTestCase lub FooAcceptanceTestCase) - ponieważ jest to przypadek testowy. na http://xunitpatterns.com/ można znaleźć niektóre standardowe konwencje nazewnictwa, takie jak test, przypadek testowy, urządzenie testowe, metoda testowa itp.


źródło