Birim testi adlandırma en iyi uygulamaları [kapalı]


564

Birim test sınıflarını ve test yöntemlerini adlandırmak için en iyi uygulamalar nelerdir?

Bu daha önce SO üzerinde tartışıldı, Ünite Testleri için bazı popüler adlandırma kuralları nelerdir?

Bunun çok iyi bir yaklaşım olup olmadığını bilmiyorum, ancak şu anda test projelerimde, her üretim sınıfı ile bir test sınıfı arasında bire bir eşlemelerim var, örn. ProductVe ProductTest.

Test sınıflarımda, test ettiğim yöntemlerin isimleri, alt çizgileri ve daha sonra durum ve ne olmasını beklediğim gibi yöntemlere sahibim Save_ShouldThrowExceptionWithNullName().



1
Bu, sorunuza cevap vermiyor, ancak okumaya değer: haacked.com/archive/2012/01/02/structuring-unit-tests.aspx
Robs

3
Google stil kılavuzu şöyle diyor: test<MethodUnderTest>_<state>örn. testPop_emptyStack Google-styleguide.googlecode.com/svn/trunk/javaguide.html 5.2.3 Yöntem adları. Şüphe duyduğunuzda Google'ı takip edin.
Ciro Santilli 法轮功 at 病 六四 事件 法轮功

2
Ve bir sonraki cümle şöyle diyor: "Test yöntemlerini adlandırmanın tek bir doğru yolu yok". Git şekil.
user2418306

1
Yıllar sonra bile Phil Haack'in tavsiyesini tercih ediyorum .
pimbrouwers

Yanıtlar:


524

Roy Osherove'nin adlandırma stratejisini seviyorum , şu:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Yöntem adı ve yapılandırılmış bir şekilde gereken her bilgiye sahiptir.

Çalışma birimi tek bir yöntem, bir sınıf veya çok sayıda sınıf kadar büyük olabilir. Bu test durumunda test edilecek ve kontrol altında olan her şeyi temsil etmelidir.

Montajlar .Testsiçin sınıflar için oldukça yaygın ve aynı olduğunu düşündüğüm tipik bir son kullanıyorum (ile biten Tests):

[NameOfTheClassUnderTestTests]

Daha önce Fikstürü Testler yerine sonek olarak kullandım, ancak ikincisinin daha yaygın olduğunu düşünüyorum, sonra adlandırma stratejisini değiştirdim.


228
Benim için yöntem adını test yöntemine koymak hiç mantıklı değil. Ya yöntemi yeniden adlandırırsanız? Hiçbir yeniden düzenleme aracı testleri sizin için yeniden adlandırmaz. Sonunda test yöntemlerini elle yeniden adlandırırsınız veya büyük olasılıkla yanlış adlandırılmış testlere sahip olursunuz. Yorumlar gibi. Çok daha kötü o zaman hiç kod yorum değil.
Piotr Perak

80
@Peri, bence bir ödünleşme. Bir yandan test adlarınız eski olabilir, diğer yandan testinizin hangi yöntemi test ettiğini söyleyemezsiniz. İkincisinin daha sık ortaya çıktığını görüyorum.
Joel McBeth

15
Peri'nin yorumuna eklemek için - tüm yöntemler bazı eylemlerden sorumludur, örn UpdateManager.Update(). Bunu aklımda tutarak testlerimi arama eğilimindeyim WhenUpdating_State_Behaviourveya WhenUpdating_Behaviour_State. Bu şekilde, bir test adına bir yöntem adı koymaktan kaçınırken, sınıfın belirli bir eylemini test ederim. Ama en önemli şey, başarısız bir testin adını gördüğümde iş mantığının neyin başarısız olduğuna dair bir ipucuna sahip olmam gerekiyor
Ramunas

8
Resharper ve IntelliJ, muhtemelen test yönteminizi bulur ve bu araçları kullanarak yeniden adlandırırsanız / yeniden adlandırırsanız sizin için yeniden adlandırmayı önerir. Ayrıca yöntem adından bahsettiğiniz yorumlara da bakmaya çalışın ve bunları da güncelleyin.
Jeff Martin

62
İyi yöntem adları genellikle yöntemin gerçekleştirdiği eylemle aynıdır. Metodunuzdan sonra metodunuz veya metodun gerçekleştirdiği eylemden sonra isminizi adlandırmaya karar vermeniz gerekiyorsa, metodunuzu yeniden adlandırmalısınız . (Yine de her durumda değil)
Kaadzia

121

Test edilen üniteden (yani sınıf) sonra test fikstürünü adlandırırken testler için "Gerekir" adlandırma standardını takip etmek istiyorum .

Açıklamak için (C # ve NUnit kullanarak):

[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));
  }
}

Neden "Olmalı" ?

Test yazarlarını sınamayı, "[bir durumda olmalı] [sonra / önce / ne zaman] [eylem gerçekleşir]” satırları boyunca bir cümle olarak adlandırmaya zorladığını görüyorum.

Evet, her yerde “Olmalı” yazmak biraz tekrarlanıyor, ama dediğim gibi yazarları doğru şekilde düşünmeye zorluyor (acemiler için de iyi olabilir). Ayrıca genellikle okunabilir bir İngilizce test adıyla sonuçlanır.

Güncelleme :

Jimmy Bogard'ın da 'olmazsa olmaz' hayranı olduğunu ve bile Should adında bir birim test kütüphanesi olduğunu fark ettim .

Güncelleme (4 yıl sonra ...)

İlgilenenler için, test adlandırma yaklaşımım yıllar içinde gelişti. Yukarıda tanımlamam gereken Should deseniyle ilgili sorunlardan biri, hangi yöntemin test edildiğini bir bakışta bilmek kolay değildir. OOP için test adını test edilen yöntemle başlatmanın daha anlamlı olduğunu düşünüyorum. İyi tasarlanmış bir sınıf için bu, okunabilir test yöntemi adlarıyla sonuçlanmalıdır. Şimdi benzer bir biçim kullanıyorum <method>_Should<expected>_When<condition>. Açıkçası bağlama bağlı olarak gerekir / ne zaman fiil yerine daha uygun bir şey yerine isteyebilirsiniz. Misal: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()


32
Hatta belki de daha iyi ve daha az gereksiz, sadece test çalışmasının varsayarak, ne söyleyen bir cümle yazar: increasesBalanceWhenDepositIsMade().
9:12

3
Son zamanlarda benzer bir adlandırma kuralından bahseden bir makale gördüm (yer işareti koymuş olsaydım). Test fikstürüne göre sıralandığında test listelerini çok okunabilir hale getirmek için tasarlanmıştır. "BankAccount" gibi bir şey görüyorsunuz, altında (farklı satırlarda) "Should_Increase_Balance_When_Deposit_Is_Made" "Should_Decrease_Balance_When_Withdrawal_Is_Made" vb.
Simon Tewsi

Makaleyi buldu. Justin Etheredge'nin CodeThinked blogunda Moq 3 ile Mocking'e Başlamak - Bölüm 1 .
Simon Tewsi

11
Ayrıca gerekir ve ne zaman kullanın ama tam tersi. örneğin WhenCustomerDoesNotExist_ShouldThrowException (). Bana göre bu, Ne Zaman Olmalı? Bu aynı zamanda AAA ile de uyuyor (Düzenleme, Hareket, Assert) ... Assert sonunda ... başlangıç ​​değil ;-)
bytedev

2
@Schneider: o zaman isteğe bağlı "gerekir" = "tavsiye" düşünüyor, merak ediyorum: daha sonra gerekli / zorunlu "gerekir" = "gerekir" kullanmak lexicaly olmaz mıydı. Örneğin, RFC'ler her ikisi arasında fark yaratır. Bu yüzden test geçişi yaptırmanız tavsiye edilir mi?
blackwizard

79

Bu adlandırma stilini beğendim:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

ve bunun gibi. Test kullanıcısı olmayan biri için sorunun ne olduğunu gerçekten netleştirir.


63
ancak @ hotshot309, .NET kullanıyor olabilir. - .NET Capitalization Conventions
Ace

2
@Ace, sana tamamen katılıyorum ve bu yorumu gönderdikten yaklaşık bir dakika sonra bunu fark ettim. Hatamı gördüğümde sildiğime yemin ettim, ama bir şekilde sanırım yapmadım. Bunun için üzgünüm.
hotshot309

3
@CoffeeAddict çünkü tanımlayıcılar içindeki alt çizgiler bir <del> sapma </del> C # gerçekten deyimsel değil
Sklivvz

2
Ben de kullanımını önlemek ister shouldtercih edecektir I willyüzdenOrdersWithNoProductsWillFail()
Calin'i

4
@Calin Bence kullanmak Willgerçekten uygun değil ve bunu yaparak aslında okuyucuya yanlışlıkla testin hiçbir şekilde başarısız olmayacağını ... Willgelecekte gerçekleşmeyebilecek bir şeyi ifade etmek için kullanırsanız, yanlış kullanmak Should, burada daha iyi bir seçimdir, çünkü bir şey olmasını istediğinizi / dilediğinizi gösterir, ancak olmadı veya yapamadı, test çalıştırıldığında başarısız / başarılı olup olmadığını söyler, böylece gerçekten ima edemezsiniz. önceden bunun mantıklı açıklaması bu, seninki ne? Neden kaçıyorsun Should?
Eyal Solnik

51

Kent Beck şunları öneriyor:

  • 'Birim' başına bir test fikstürü (programınızın sınıfı). Test fikstürleri sınıfların kendisidir. Test fikstürünün adı:

    [name of your 'unit']Tests
    
  • Test senaryoları (test fikstürü yöntemleri) aşağıdaki gibi isimlere sahiptir:

    test[feature being tested]
    

Örneğin, aşağıdaki sınıfa sahip olanlar:

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

    // other methods and properties
}

Bir test fikstürü:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}

4
Keşke daha fazla insan bu yönergeleri izlese. Çok uzun zaman önce, "ATest", "BasicTest" veya "ErrorTest" gibi isimleri olduğu için 20'den fazla test yöntemini yeniden adlandırmak zorunda kaldım.
Kama

85
sınıfın soneki göz önüne alındığında 'test' yöntem öneki gereksiz olmaz mı?
Gavin Miller

50
Kent bu kitabı yazdığında bunu hatırla. Öznitelikler icat edilmedi. Bu nedenle yöntem adındaki Test adı, test çerçevesine yöntemin bir test olduğunu belirtir. 2002'den beri de çok şey oldu.
Thomas Jespersen

14
testCalculateAge ... Bu, test yönteminiz için anlamsız bir addır. "test" gereksizdir (tüm yöntemlerinizi "method" önekiyle adlandırır mısınız?). İsmin geri kalanında test edilen herhangi bir koşul veya ne bekleniyordu. CalculateAge test edilen yöntem mi? ..... kim bilir ...
bytedev

1
Bu stratejiyi kullanırken, beklenen çıktıyı belirtmek için dokümantasyonun gerekli olduğunu eklemek istiyorum. 'Test' öneki hakkında bir yan not olarak; bazı birim test çerçeveleri, testleri tanımak için belirli ön ekler veya sonekler gerektirir. Soyut sınıfların 'Soyut' ile ön eki gereksiz olarak kabul edilmez (çünkü kendi kendini belgelediği için), neden aynı şey 'Test' için geçerli değildir?
siebz0r

17

Sınıf İsimleri . Test fikstürü adları için, "Test" in birçok alanın her yerde her yerde yaygın olduğunu görüyorum. Örneğin, bir mühendislik alanında: StressTestve kozmetik alanında: SkinTest. Kent ile aynı fikirde olmadığım için üzgünüm, ancak test fikstürlerimde "Test" i (StressTestTest ?) kafa karıştırıcı.

"Birim" alan adlarında da çok kullanılır. Örn MeasurementUnit. Bir sınıfa MeasurementUnitTest"Measurement" veya "MeasurementUnit" testi denir mi?

Bu nedenle tüm test sınıflarım için "Qa" önekini kullanmayı seviyorum. ÖrneğinQaSkinTest ve QaMeasurementUnit. Etki alanı nesneleriyle asla karıştırılmaz ve sonek yerine bir önek kullanmak, tüm test fikstürlerinin görsel olarak birlikte yaşadığı anlamına gelir (test projenizde sahte veya diğer destek sınıflarınız varsa yararlıdır)

Ad alanları . C # çalışıyorum ve test sınıfları test ettikleri sınıfla aynı ad alanında tutmak. Ayrı test ad alanlarına sahip olmaktan daha uygundur. Elbette, test sınıfları farklı bir projede.

Test yöntemi adları . Yöntemlerimi WhenXXX_ExpectYYY olarak adlandırmak istiyorum. Ön koşulu netleştirir ve otomatik dokümantasyona (a TestDox) yardımcı olur. Bu, Google test blogundaki tavsiyeye benzer, ancak önkoşul ve beklentilerin daha fazla ayrılmasıyla. Örneğin:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory

test yöntemi adları ve test fikstürü adları hakkında konuştunuz. test fikstürü adları üretim sınıflarıyla eşleştirilir. testinizde üretim yöntemi adını nereye yazıyorsunuz?
Işık

12

Ben kullanın Verilen-O zaman kavramı. Bu kısa makaleye bir göz atın http://cakebaker.42dh.com/2009/05/28/given-when-then/ . Makale bu kavramı BDD açısından açıklamaktadır, ancak TDD'de de herhangi bir değişiklik yapmadan kullanabilirsiniz.


Verilen-When-Then MethodName_Scenario_ExpectedBehavior ile aynı, değil mi ?!
Işık

1
Tam olarak değil. Given_When_Then şunlara daha fazla atıfta bulunur: GivenAnEntity_WhenSomeActionHappens_ThatResultIsExpected Test, bir uygulama değil bir davranışı test etme iradesini ifade etmelidir .
plog17

1
"O Zaman Verilenler" genellikle Kornişon olarak adlandırılır. Salatalık, JBehave ve Behat araçlarından çıkan bir DSL.
bytedev

+1 bu en iyi yöntem imo. Bir yöntemin sonucun olmasını beklediğiniz şeyden nasıl bir şey yaptığını ayırmak çok güçlüdür ve diğer yorumlarda açıklanan birçok sorunu önler.
Lee


7

En önemli şeylerden birinin adlandırma sözleşmenizde tutarlı olduğunu düşünüyorum (ve ekibinizin diğer üyeleriyle aynı fikirdeyim). Birçok kez aynı projede birçok farklı konvansiyon kullanıldığını görüyorum.


7

Kısa bir süre önce, tanımlamaları en üst düzeye çıkarmak için testlerimi, sınıflarını ve projelerini adlandırmak için aşağıdaki sözleşmeyi yaptım:

Diyelim ki Settingssınıfı MyApp.Serializationisim alanındaki bir projede test ediyorum .

İlk olarak, MyApp.Serialization.Testsad alanı ile bir test projesi oluşturacağım .

Bu proje içinde ve tabii ki isim alanında IfSettings( IfSettings.cs olarak kaydedilmiş ) adında bir sınıf oluşturacağım .

Diyelim ki SaveStrings()yöntemi test ediyorum . -> Testi adlandıracağım CanSaveStrings().

Bu testi çalıştırdığımda şu başlığı gösterecektir:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Bence bu çok iyi anlatıyor, ne test ediyor.

Tabii ki İngilizce'de "Testler" isminin "testler" fiili ile aynı olması yararlıdır.

Testleri adlandırırken yaratıcılığınızın bir sınırı yoktur, böylece onlar için tam cümle başlıkları alırız.

Genellikle Test isimlerinin bir fiil ile başlaması gerekir.

Örnekler:

  • Algılar (ör. DetectsInvalidUserInput)
  • Atar (ör. ThrowsOnNotFound)
  • Will (örneğin WillCloseTheDatabaseAfterTheTransaction)

vb.

Başka bir seçenek de "if" yerine "that" kullanmaktır.

İkincisi Bana rağmen tuş vuruşlarını ve ben bilmiyorum çünkü, ne yapıyorum daha tam olarak tarif eder kaydeder olduğunu test davranış mevcut olmakla birlikte, test ediyorum eğer öyle.

[ Düzenle ]

Yukarıdaki adlandırma kuralını biraz daha uzun süre kullandıktan sonra , arayüzlerle çalışırken If önekinin kafa karıştırıcı olabileceğini buldum . Öyle ki, IfSerializer.cs test sınıfı "Open Files Sekmesi" ndeki ISerializer.cs arayüzüne çok benziyor . Bu, testler, test edilen sınıf ve arayüzü arasında ileri geri geçiş yaparken çok can sıkıcı olabilir. Sonuç olarak ben şimdi seçsin Yani üzerinde If önek olarak.

Ayrıca şimdi - sadece test sınıflarımdaki yöntemler için başka hiçbir yerde en iyi uygulama olarak kabul edilmez - "_" benim gibi test yöntemi adları kelime ayırmak için kullanın:

[Test] public void detects_invalid_User_Input()

Bunu okumayı daha kolay buluyorum.

[ Düzenlemeyi Sonlandır ]

Umarım bu daha fazla fikir ortaya çıkarır, çünkü testlerin ne yaptığını anlamaya çalışmak için harcanan çok fazla zaman kazandırabileceği için büyük önem taşıyan testleri adlandırmayı düşünürüm (örneğin, genişletilmiş bir aradan sonra bir projeye devam ettikten sonra) .


2

VS + NUnit'te genellikle fonksiyonel testleri birlikte gruplandırmak için projemde klasörler oluştururum. Sonra birim test fikstür sınıfları oluşturmak ve bunları test ediyorum işlevsellik türü sonra adlandırın. [Test] yöntemleri şu satırlarda adlandırılır 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

2

Testlerinizi aynı pakette ancak test edilen kaynağa paralel bir dizinde tutmanın, bir sürü dışlama deseni yapmak zorunda kalmadan konuşlandırmaya hazır olduğunuzda kodun şişmesini ortadan kaldırdığını eklemeliyim.

Şahsen "JUnit Pocket Guide" da açıklanan en iyi uygulamaları seviyorum ... JUnit'in ortak yazarı tarafından yazılmış bir kitabı yenmek zor!


3
Bunun aslında eldeki soruya cevap verdiğine inanmayın - JUnit Pocket Guide'da düzenleme ve başvuru yapabilir misiniz? Teşekkürler!
Nate-Wilkins

0

Foo sınıfı için test senaryosunun adı FooTestCase veya bunun gibi bir şey olmalıdır (FooIntegrationTestCase veya FooAcceptanceTestCase) - çünkü bir test vakasıdır. test, test durumu, test fikstürü, test yöntemi vb. gibi bazı standart adlandırma kuralları için http://xunitpatterns.com/ adresine bakın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.