Praktik terbaik penamaan unit test [ditutup]

564

Apa praktik terbaik untuk penamaan kelas tes unit dan metode pengujian?

Ini telah dibahas pada SO sebelumnya, di Apa saja konvensi penamaan populer untuk Tes Unit?

Saya tidak tahu apakah ini pendekatan yang sangat baik, tetapi saat ini dalam proyek pengujian saya, saya memiliki pemetaan satu-ke-satu antara setiap kelas produksi dan kelas pengujian, misalnya Productdan ProductTest.

Di kelas pengujian saya, saya kemudian memiliki metode dengan nama metode yang saya uji, garis bawah, dan kemudian situasi dan apa yang saya harapkan terjadi, misalnya Save_ShouldThrowExceptionWithNullName().

James Newton-King
sumber
Lihat di sini: stackoverflow.com/questions/96297/…
Forgotten Semicolon
1
Ini tidak menjawab pertanyaan Anda, tapi layak baca: haacked.com/archive/2012/01/02/structuring-unit-tests.aspx
Robs
3
Panduan gaya Google mengatakan :,test<MethodUnderTest>_<state> misalnya testPop_emptyStack google-styleguide.googlecode.com/svn/trunk/javaguide.html 5.2.3 Nama metode. Jika ragu, ikuti Google.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
@CiroSantilli 六四 事件 法轮功 包 卓 轩 Dan kalimat berikutnya mengatakan: "Tidak ada Satu Cara yang Benar untuk menyebutkan metode pengujian". Sosok pergi.
user2418306
1
Saya masih lebih suka rekomendasi Phil Haack bahkan bertahun-tahun kemudian.
pimbrouwers

Jawaban:

524

Saya suka strategi penamaan Roy Osherove , berikut ini:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Ia memiliki setiap informasi yang diperlukan tentang nama metode dan secara terstruktur.

Unit kerja bisa sekecil metode tunggal, satu kelas, atau sebesar beberapa kelas. Ini harus mewakili semua hal yang harus diuji dalam kasus uji ini dan terkendali.

Untuk majelis saya menggunakan .Testsakhiran yang khas , yang menurut saya cukup luas dan sama untuk kelas (diakhiri dengan Tests):

[NameOfTheClassUnderTestTests]

Sebelumnya saya menggunakan Fixture sebagai suffix sebagai ganti Tes tapi saya pikir yang terakhir lebih umum, kemudian saya mengubah strategi penamaan.

Marc Climent
sumber
228
Bagi saya tidak masuk akal untuk memasukkan nama metode dalam metode pengujian. Bagaimana jika Anda mengganti nama metode? Tidak ada alat refactoring yang akan mengganti nama tes untuk Anda. Akhirnya Anda akhirnya mengganti nama metode pengujian dengan tangan atau lebih mungkin memiliki tes yang salah nama. Seperti dengan komentar. Jauh lebih buruk daripada tidak berkomentar kode sama sekali.
Piotr Perak
80
@Peri, saya pikir itu adalah tradeoff. Di satu sisi nama tes Anda mungkin menjadi ketinggalan zaman, di sisi lain Anda tidak dapat mengatakan metode apa yang diuji. Saya menemukan yang terakhir muncul jauh lebih sering.
Joel McBeth
15
Untuk menambahkan komentar Peri - semua metode bertanggung jawab untuk beberapa tindakan, misalnya UpdateManager.Update(). Memiliki ini dalam pikiran saya cenderung untuk memanggil tes saya WhenUpdating_State_Behaviouratau WhenUpdating_Behaviour_State. Dengan cara ini saya menguji tindakan tertentu dari suatu kelas sambil menghindari untuk memasukkan nama metode dalam nama tes. Tetapi yang paling penting adalah bahwa saya harus memiliki petunjuk tentang logika bisnis yang gagal ketika saya melihat nama tes yang gagal
Ramunas
8
Resharper dan IntelliJ mungkin akan menemukan metode pengujian Anda dan menawarkan untuk mengganti nama untuk Anda jika Anda refactored / diganti namanya menggunakan alat-alat itu. Juga mencoba untuk melihat di komentar di mana Anda menyebutkan nama metode dan perbarui juga.
Jeff Martin
62
Nama-nama metode yang baik sering kali sama dengan aksi metode perfom. Jika Anda harus memutuskan antara memberi nama tes setelah metode Anda atau tindakan metode yang melakukan itu mungkin merupakan petunjuk Anda harus mengganti nama metode Anda . (Tidak dalam setiap kasus)
Kaadzia
121

Saya suka mengikuti standar penamaan "Harus" untuk tes sambil memberi nama perlengkapan tes setelah unit yang diuji (yaitu kelas).

Untuk menggambarkan (menggunakan C # dan 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));
  }
}

Kenapa "Harus" ?

Saya menemukan bahwa itu memaksa penulis tes untuk memberi nama tes dengan kalimat di sepanjang baris "Harus [berada di beberapa negara] [setelah / sebelum / ketika] [tindakan terjadi]"

Ya, menulis "Seharusnya" di mana-mana memang sedikit berulang, tetapi seperti yang saya katakan itu memaksa penulis untuk berpikir dengan cara yang benar (jadi bisa baik untuk pemula). Plus itu umumnya menghasilkan nama tes bahasa Inggris yang dapat dibaca.

Perbarui :

Saya perhatikan bahwa Jimmy Bogard juga penggemar 'harus' dan bahkan memiliki perpustakaan tes unit yang disebut Harus .

Perbarui (4 tahun kemudian ...)

Bagi mereka yang tertarik, pendekatan saya untuk tes penamaan telah berkembang selama bertahun-tahun. Salah satu masalah dengan pola Haruskah saya jelaskan di atas sebagai tidak mudah untuk mengetahui sekilas metode mana yang sedang diuji. Untuk OOP saya pikir lebih masuk akal untuk memulai nama uji dengan metode yang diuji. Untuk kelas yang dirancang dengan baik ini harus menghasilkan nama metode uji yang dapat dibaca. Saya sekarang menggunakan format yang mirip dengan <method>_Should<expected>_When<condition>. Jelas tergantung pada konteksnya Anda mungkin ingin mengganti kata kerja Should / When dengan sesuatu yang lebih tepat. Contoh: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()

Jack Ukleja
sumber
32
Bahkan mungkin lebih baik dan kurang berlebihan, hanya menulis sebuah kalimat yang memberitahu apa yang dilakukannya, dengan asumsi tes bekerja: increasesBalanceWhenDepositIsMade().
hotshot309
3
Baru-baru ini melihat sebuah artikel yang menyebutkan konvensi penamaan yang serupa (berharap saya menandainya). Dirancang untuk membuat daftar tes sangat mudah dibaca ketika diurutkan berdasarkan perlengkapan tes. Anda melihat sesuatu seperti "BankAccount" lalu di bawahnya (pada baris yang berbeda) "Should_Increase_Balance_When_Deposit_Is_Made" "Should_Decrease_Balance_When_Withdrawal_Is_Made", dll. Sangat mirip dengan spesifikasi, yang merupakan jenis TDD.
Simon Tewsi
Ditemukan artikelnya. Ada di blog CodeThinked Justin Etheredge Dimulai Mengejek Dengan Moq 3 - Bagian 1 .
Simon Tewsi
11
Saya juga menggunakan Should dan When tetapi sebaliknya. misal WhenCustomerDoesNotExist_ShouldThrowException (). Bagi saya ini jauh lebih masuk akal daripada Seharusnya Saat (yaitu dalam skenario tertentu harus ada hasil yang diharapkan tertentu). Ini juga cocok dengan AAA (Atur, Bertindak, Tegas) ... Tegas pada akhirnya ... bukan awalnya ;-)
bytedev
2
@ Schneider: mempertimbangkan "harus" = "direkomendasikan" maka opsional, saya bertanya-tanya: bukankah lebih baik untuk menggunakan "shall" = "must" maka diperlukan / wajib. Misalnya, RFC membuat perbedaan di antara keduanya. Jadi direkomendasikan atau diperlukan tes lulus?
blackwizard
79

Saya suka gaya penamaan ini:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

dan seterusnya. Sangat jelas bagi non-tester apa masalahnya.

Sklivvz
sumber
63
tapi @ hotshot309, dia mungkin menggunakan .NET - .NET Capitalization Convention
Ace
2
@Ace, saya sangat setuju dengan Anda dan memperhatikan ini sekitar satu menit setelah saya memposting komentar ini. Saya bersumpah bahwa saya menghapusnya ketika saya melihat kesalahan saya, tetapi entah bagaimana, saya kira saya tidak melakukannya. Maaf soal itu.
hotshot309
3
@CoffeeAddict karena garis bawah di dalam pengidentifikasi adalah <del> aberration </del> tidak benar-benar idiomatis dalam C #
Sklivvz
2
Saya juga ingin menghindari penggunaan dari shouldsaya akan lebih memilih willjadiOrdersWithNoProductsWillFail()
Calin
4
@Calin Menurut pendapat saya menggunakan Willtidak benar-benar tepat dan dengan melakukan itu Anda benar-benar keliru mengatakan kepada pembaca bahwa tes tidak akan gagal ... jika Anda menggunakan Willuntuk mengekspresikan sesuatu di masa depan yang mungkin tidak terjadi Anda menggunakannya secara salah sedangkan itu Shouldadalah pilihan yang lebih baik di sini karena itu menunjukkan bahwa Anda ingin / berharap sesuatu terjadi tetapi tidak atau tidak bisa, ketika tes berjalan itu memberitahu Anda apakah itu gagal / berhasil sehingga Anda tidak dapat benar-benar menyiratkan bahwa sebelumnya, itulah penjelasan logis untuk itu, apa milikmu? mengapa Anda menghindari Should?
Eyal Solnik
51

Kent Beck menyarankan:

  • Satu perlengkapan tes per 'unit' (kelas program Anda). Perlengkapan ujian adalah kelas itu sendiri. Nama perlengkapan uji harus:

    [name of your 'unit']Tests
    
  • Kasus uji (metode perlengkapan uji) memiliki nama seperti:

    test[feature being tested]
    

Misalnya, memiliki kelas berikut:

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

    // other methods and properties
}

Perlengkapan ujian adalah:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}
Sergio Acosta
sumber
4
Saya berharap lebih banyak orang akan mengikuti pedoman ini. Belum lama ini saya harus mengganti nama lebih dari 20 metode pengujian karena mereka memiliki nama seperti "ATest", "BasicTest", atau "ErrorTest".
Wedge
85
bukankah awalan metode 'tes' menjadi berlebihan mengingat akhiran kelas?
Gavin Miller
50
Ingat itu ketika Kent menulis buku itu. Atribut tidak ditemukan. Oleh karena itu nama Uji dalam nama metode ditunjukkan ke kerangka uji bahwa metode tersebut adalah tes. Juga banyak yang telah terjadi sejak tahun 2002.
Thomas Jespersen
14
testCalculateAge ... ini adalah nama yang tidak berarti untuk metode pengujian Anda. "test" berlebihan (apakah Anda menyebutkan semua metode Anda dengan awalan "metode"?). Sisa nama tidak memiliki kondisi yang diuji atau apa yang diharapkan. Apakah CalculateAge metode yang diuji? ..... siapa yang tahu ...
bytedev
1
Saya ingin menambahkan bahwa ketika menggunakan strategi ini, dokumentasi diperlukan untuk menentukan output yang diharapkan. Sebagai catatan tambahan tentang awalan 'test'; beberapa kerangka kerja unit pengujian memerlukan awalan atau sufiks tertentu untuk mengenali pengujian. Mengawali kelas abstrak dengan 'Abstrak' tidak dianggap berlebihan (karena itu mendokumentasikan diri), jadi mengapa tidak berlaku sama dengan 'Tes'?
siebz0r
17

Nama Kelas . Untuk nama perlengkapan tes, saya menemukan bahwa "Tes" cukup umum dalam bahasa di mana-mana banyak domain. Sebagai contoh, dalam domain engineering: StressTest, dan dalam domain kosmetik: SkinTest. Maaf tidak setuju dengan Kent, tetapi menggunakan "Tes" pada jadwal pengujian saya ( StressTestTest?) Membingungkan.

"Unit" juga banyak digunakan dalam domain. Misalnya MeasurementUnit. Apakah kelas disebut MeasurementUnitTesttes "Pengukuran" atau "PengukuranUnit"?

Karena itu saya suka menggunakan awalan "Qa" untuk semua kelas ujian saya. Misalnya QaSkinTestdan QaMeasurementUnit. Tidak pernah bingung dengan objek domain, dan menggunakan awalan daripada akhiran berarti bahwa semua perlengkapan tes hidup bersama secara visual (berguna jika Anda memiliki palsu atau kelas pendukung lainnya dalam proyek pengujian Anda)

Ruang nama . Saya bekerja di C # dan saya menjaga kelas pengujian saya di namespace yang sama dengan kelas yang mereka uji. Ini lebih nyaman daripada memiliki ruang nama tes terpisah. Tentu saja, kelas tes berada di proyek yang berbeda.

Nama metode uji . Saya suka memberi nama metode saya WhenXXX_ExpectYYY. Itu membuat prasyarat jelas, dan membantu dengan dokumentasi otomatis (ala TestDox). Ini mirip dengan saran di blog pengujian Google, tetapi dengan lebih banyak pemisahan prasyarat dan harapan. Sebagai contoh:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory
grundoon
sumber
Anda berbicara tentang nama metode pengujian dan nama perlengkapan tes. nama perlengkapan tes dipetakan ke kelas produksi. di mana Anda menulis nama metode produksi dalam pengujian Anda?
The Light
12

Saya menggunakan konsep Given-When-Then . Lihatlah artikel pendek ini http://cakebaker.42dh.com/2009/05/28/given-when-then/ . Artikel menjelaskan konsep ini dalam hal BDD, tetapi Anda dapat menggunakannya dalam TDD juga tanpa perubahan.

Pashec
sumber
Mengingat-Kapan-Lalu sama dengan MethodName_Scenario_ExpectedBehavior, bukan ?!
The Light
1
Tidak persis. Diberikan_Ketika_Kemudian mengacu lebih ke: DiberikanAnEntity_Ketika AdaAksi Terjadi_ThatResultIpa yang Diharapkan Tes harus menyatakan keinginan untuk menguji perilaku bukan implementasi .
plog17
1
"Given When Then" sering disebut sebagai Gherkin. Ini adalah DSL yang keluar dari alat Mentimun, JBehave dan Behat.
bytedev
+1 ini adalah metode imo terbaik. Memisahkan bagaimana suatu metode melakukan sesuatu dari apa yang Anda harapkan hasilnya sangat kuat dan menghindari banyak masalah yang dijelaskan dalam komentar lain.
Lee
7

Saya pikir salah satu hal terpenting adalah konsisten dalam konvensi penamaan Anda (dan sepakati dengan anggota tim Anda yang lain). Berkali-kali saya melihat banyak konvensi berbeda yang digunakan dalam proyek yang sama.

bytedev
sumber
7

Saya baru-baru ini datang dengan konvensi berikut untuk penamaan tes saya, kelas mereka dan berisi proyek untuk memaksimalkan deskripsi mereka:

Katakanlah saya sedang menguji Settingskelas dalam sebuah proyek di MyApp.Serializationnamespace.

Pertama saya akan membuat proyek uji dengan MyApp.Serialization.Testsnamespace.

Dalam proyek ini dan tentu saja namespace saya akan membuat kelas yang disebut IfSettings(disimpan sebagai IfSettings.cs ).

Katakanlah saya sedang menguji SaveStrings()metode. -> Saya akan memberi nama tes CanSaveStrings().

Saat saya menjalankan tes ini, ia akan menampilkan tajuk berikut:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Saya pikir ini memberitahu saya dengan sangat baik, apa itu pengujian.

Tentu saja bermanfaat bahwa dalam bahasa Inggris kata benda "Tes" sama dengan kata kerja "tes".

Tidak ada batasan untuk kreativitas Anda dalam memberi nama tes, sehingga kami mendapatkan judul kalimat penuh untuk mereka.

Biasanya nama Test harus diawali dengan kata kerja.

Contohnya termasuk:

  • Mendeteksi (mis. DetectsInvalidUserInput)
  • Melempar (misalnya ThrowsOnNotFound)
  • Will (eg WillCloseTheDatabaseAfterTheTransaction)

dll.

Pilihan lain adalah menggunakan "itu" daripada "jika".

Yang terakhir menyelamatkan saya penekanan tombol dan menjelaskan lebih tepatnya apa yang saya lakukan, karena saya tidak tahu, bahwa perilaku yang diuji ada, tetapi saya menguji apakah itu.

[ Sunting ]

Setelah menggunakan konvensi penamaan di atas untuk sedikit lebih lama sekarang, saya telah menemukan, bahwa awalan If dapat membingungkan, ketika bekerja dengan antarmuka. Kebetulan, bahwa kelas pengujian IfSerializer.cs terlihat sangat mirip dengan antarmuka ISerializer.cs di "Buka File Tab". Ini bisa sangat menjengkelkan ketika beralih bolak-balik antara tes, kelas yang diuji dan antarmuka-nya. Alhasil saya sekarang akan memilih That over If sebagai awalan.

Selain itu saya sekarang menggunakan - hanya untuk metode di kelas pengujian saya karena tidak dianggap praktik terbaik di tempat lain - "_" untuk memisahkan kata dalam nama metode pengujian saya seperti pada:

[Test] public void detects_invalid_User_Input()

Saya menemukan ini lebih mudah dibaca.

[ Akhir Edit ]

Saya harap ini memunculkan beberapa ide lagi, karena saya menganggap penamaan tes sangat penting karena dapat menghemat banyak waktu yang seharusnya dihabiskan untuk mencoba memahami apa yang dilakukan tes (misalnya setelah melanjutkan proyek setelah jeda panjang) .

Thorsten Lorenz
sumber
2

Dalam VS + NUnit saya biasanya membuat folder di proyek saya untuk mengelompokkan tes fungsional bersama. Kemudian saya membuat kelas-kelas perlengkapan pengujian unit dan memberi nama mereka setelah jenis fungsionalitas yang saya uji. Metode [Tes] diberi nama di sepanjang baris 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
sumber
2

Saya harus menambahkan bahwa menjaga tes Anda dalam paket yang sama tetapi dalam direktori paralel ke sumber yang diuji menghilangkan mengasapi kode setelah Anda siap untuk menyebarkannya tanpa harus melakukan banyak pola mengecualikan.

Saya pribadi menyukai praktik terbaik yang dijelaskan dalam "Panduan Saku JUnit" ... sulit untuk mengalahkan buku yang ditulis oleh rekan penulis JUnit!

Steve Moyer
sumber
3
Jangan percaya ini benar-benar menjawab pertanyaan yang ada - bisakah Anda membuat suntingan dan referensi Panduan Saku JUnit? Terima kasih!
Nate-Wilkins
0

nama kasus uji untuk kelas Foo haruslah FooTestCase atau semacamnya (FooIntegrationTestCase atau FooAcceptanceTestCase) - karena merupakan kasus uji. lihat http://xunitpatterns.com/ untuk beberapa konvensi penamaan standar seperti tes, test case, fixture tes, metode pengujian, dll.


sumber