Bài kiểm tra đơn vị thực hành tốt nhất [đóng]


564

Các thực hành tốt nhất để đặt tên các lớp kiểm tra đơn vị và phương pháp kiểm tra là gì?

Điều này đã được thảo luận trên SO trước đây, tại một số quy ước đặt tên phổ biến cho các bài kiểm tra đơn vị là gì?

Tôi không biết liệu đây có phải là một cách tiếp cận rất tốt hay không, nhưng hiện tại trong các dự án thử nghiệm của tôi, tôi có các ánh xạ một-một giữa mỗi lớp sản xuất và một lớp thử nghiệm, ví dụ ProductProductTest.

Trong các lớp kiểm tra của tôi, sau đó tôi có các phương thức với tên của các phương thức tôi đang kiểm tra, một dấu gạch dưới, và sau đó là tình huống và những gì tôi dự kiến ​​sẽ xảy ra, ví dụ Save_ShouldThrowExceptionWithNullName().



1
Điều này không trả lời câu hỏi của bạn, nhưng đáng để đọc: haacked.com/archive/2012/01/02/structuring-unit-tests.aspx
Cướp

3
Hướng dẫn về phong cách của Google cho biết : test<MethodUnderTest>_<state>, ví dụ: testPop_emptyStack google-styleguide.googlecode.com/svn/trunk/javaguide.html 5.2.3 Tên phương thức. Khi nghi ngờ, hãy theo dõi Google.
Ciro Santilli 郝海东 冠状 病 事件

2
@CiroSantilli 事件 法轮功 包 卓 轩 Và câu tiếp theo nói: "Không có cách nào đúng để đặt tên phương pháp kiểm tra". Đi hình.
dùng2418306

1
Tôi vẫn thích khuyến nghị của Phil Haack ngay cả nhiều năm sau đó.
pimbrouwers

Câu trả lời:


524

Tôi thích chiến lược đặt tên của Roy Osherove , đó là:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Nó có mọi thông tin cần thiết về tên phương thức và theo cách có cấu trúc.

Đơn vị công việc có thể nhỏ như một phương thức, một lớp hoặc lớn bằng nhiều lớp. Nó nên đại diện cho tất cả những điều sẽ được kiểm tra trong trường hợp thử nghiệm này và đang được kiểm soát.

Đối với các hội đồng tôi sử dụng .Testskết thúc điển hình , mà tôi nghĩ là khá phổ biến và giống nhau cho các lớp (kết thúc bằng Tests):

[NameOfTheClassUnderTestTests]

Trước đây tôi đã sử dụng Fixture như hậu tố thay vì Tests nhưng tôi nghĩ cái sau phổ biến hơn, sau đó tôi đã thay đổi chiến lược đặt tên.


228
Đối với tôi không có nghĩa gì khi đặt tên phương thức trong phương thức thử nghiệm. Nếu bạn đổi tên phương thức thì sao? Không có công cụ tái cấu trúc sẽ đổi tên các bài kiểm tra cho Bạn. Cuối cùng, bạn kết thúc việc đổi tên phương thức kiểm tra bằng tay hoặc nhiều khả năng có các bài kiểm tra được đặt tên sai. Nó giống như với ý kiến. Để nhiều là tồi tệ hơn sau đó không bình luận mã.
Piotr Perak

80
@Peri, tôi nghĩ đó là một sự đánh đổi. Một mặt, tên thử nghiệm của bạn có thể trở nên lỗi thời, mặt khác, bạn không thể biết phương pháp thử nghiệm của mình đang thử nghiệm. Tôi tìm thấy cái sau xuất hiện thường xuyên hơn nhiều.
Joel McBeth

15
Để thêm vào bình luận Peri - tất cả các phương pháp có trách nhiệm đối với một số hành động, ví dụ UpdateManager.Update(). Có điều này trong tâm trí tôi có xu hướng gọi các bài kiểm tra của tôi WhenUpdating_State_Behaviourhoặc WhenUpdating_Behaviour_State. Bằng cách này, tôi kiểm tra một hành động cụ thể của một lớp trong khi tránh đặt tên phương thức vào tên kiểm tra. Nhưng điều quan trọng nhất là tôi phải có manh mối về logic kinh doanh thất bại khi tôi thấy tên của một bài kiểm tra thất bại
Ramunas

8
Resharper và IntelliJ đều có thể tìm thấy phương pháp thử nghiệm của bạn và đề nghị đổi tên nó cho bạn nếu bạn tái cấu trúc / đổi tên bằng các công cụ đó. Họ cũng cố gắng xem các bình luận trong đó bạn đề cập đến tên phương thức và cập nhật chúng.
Jeff Martin

62
Tên phương thức tốt thường giống như hành động của phương thức. Nếu bạn phải quyết định giữa việc đặt tên thử nghiệm của mình sau phương thức của bạn hoặc hành động thì phương thức thực hiện có thể là một gợi ý bạn nên đổi tên phương thức của mình . (Không phải trong mọi trường hợp)
Kaadzia

121

Tôi thích tuân theo tiêu chuẩn đặt tên "Nên" cho các thử nghiệm trong khi đặt tên cho vật cố thử nghiệm sau đơn vị được thử nghiệm (tức là lớp).

Để minh họa (sử dụng C # và 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));
  }
}

Tại sao "nên" ?

Tôi thấy rằng nó buộc các tác giả kiểm tra đặt tên cho bài kiểm tra bằng một câu dọc theo dòng "Nên [ở trạng thái nào đó] [sau / trước / khi] [hành động diễn ra]"

Đúng, viết "Nên" ở mọi nơi sẽ có một chút lặp đi lặp lại, nhưng như tôi đã nói, nó buộc các nhà văn phải suy nghĩ theo cách chính xác (vì vậy có thể tốt cho người mới). Thêm vào đó, nó thường dẫn đến một tên kiểm tra tiếng Anh dễ đọc.

Cập nhật :

Tôi đã nhận thấy rằng Jimmy Bogard cũng là một người hâm mộ 'nên' và thậm chí còn có một thư viện thử nghiệm đơn vị tên là Should .

Cập nhật (4 năm sau ...)

Đối với những người quan tâm, cách tiếp cận của tôi để kiểm tra đặt tên đã phát triển qua nhiều năm. Một trong những vấn đề với mẫu Should tôi mô tả ở trên là không dễ để biết trong nháy mắt phương pháp nào đang được thử nghiệm. Đối với OOP tôi nghĩ sẽ hợp lý hơn khi bắt đầu tên thử nghiệm với phương thức được thử nghiệm. Đối với một lớp được thiết kế tốt, điều này sẽ dẫn đến tên phương thức thử nghiệm có thể đọc được. Bây giờ tôi sử dụng một định dạng tương tự <method>_Should<expected>_When<condition>. Rõ ràng tùy thuộc vào ngữ cảnh bạn có thể muốn thay thế các động từ Nên / Khi cho một cái gì đó phù hợp hơn. Thí dụ: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()


32
Thậm chí có thể tốt hơn và ít dư thừa hơn, chỉ cần viết một câu cho biết những gì nó làm, giả sử thử nghiệm hoạt động : increasesBalanceWhenDepositIsMade().
hotshot309

3
Gần đây đã thấy một bài viết đề cập đến một quy ước đặt tên tương tự (muốn tôi đánh dấu nó). Được thiết kế để làm cho danh sách các bài kiểm tra rất dễ đọc khi được sắp xếp theo đồ gá kiểm tra. Bạn thấy một cái gì đó như "BankAccount" sau đó (trên các dòng khác nhau) "Should_Increas_Balance_When_Deposit_Is_Made" "Should_Decreas_Balance_When_Withdrawal_Is_Made", v.v. Đọc rất giống với thông số kỹ thuật.
Simon Tewsi

Tìm thấy bài báo. Nó nằm trong CodeThinked của Justin Etheredge Bắt đầu chế giễu với Moq 3 - Phần 1 .
Simon Tewsi

11
Tôi cũng sử dụng Nên và Khi nhưng ngược lại. ví dụ: KhiCustomerDoesNotExist_ShouldThrowException (). Đối với tôi điều này có ý nghĩa hơn nhiều so với Nên sau đó Khi nào (nghĩa là trong một kịch bản nhất định sẽ có một kết quả mong đợi nhất định). Điều này cũng phù hợp với AAA (Sắp xếp, Đạo luật, Khẳng định) ... Khẳng định ở cuối ... không phải là bắt đầu ;-)
bytedev

2
@Schneider: xem xét "nên" = "được đề xuất" sau đó là tùy chọn, tôi tự hỏi: sẽ không tốt hơn nếu sử dụng "sẽ" = "phải" sau đó bắt buộc / bắt buộc. Ví dụ, RFC tạo ra sự khác biệt giữa cả hai. Vì vậy, có bài kiểm tra vượt qua được khuyến khích hoặc yêu cầu?
Blackwizard

79

Tôi thích phong cách đặt tên này:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

và như thế. Nó làm cho thực sự rõ ràng cho một người không thử nghiệm vấn đề là gì.


63
nhưng @ hotshot309, anh ta có thể đang sử dụng .NET - Các quy ước viết hoa .NET
Ace

2
@Ace, tôi hoàn toàn đồng ý với bạn và nhận thấy điều này khoảng một phút sau khi tôi đăng bình luận này. Tôi thề rằng tôi đã xóa nó khi tôi thấy lỗi của mình, nhưng bằng cách nào đó, tôi đoán là tôi đã không làm thế. Xin lỗi vì điều đó.
hotshot309

3
@CoffeeAddict vì dấu gạch dưới trong số nhận dạng là một <del> quang sai </ del> không thực sự thành ngữ trong C #
Sklivvz

2
Tôi cũng muốn tránh việc sử dụng shouldtôi sẽ thích willnhư vậyOrdersWithNoProductsWillFail()
Calin

4
@Calin Theo tôi, việc sử dụng Willkhông thực sự phù hợp và bằng cách đó bạn thực sự đã nói sai với người đọc rằng bằng mọi cách , bài kiểm tra sẽ thất bại ... nếu bạn sử dụng Willđể diễn đạt điều gì đó trong tương lai có thể không xảy ra sử dụng nó không chính xác trong khi đó Shouldlà lựa chọn tốt hơn ở đây bởi vì nó chỉ ra rằng bạn muốn / muốn điều gì đó xảy ra nhưng không hoặc không thể, khi thử nghiệm chạy, nó sẽ cho bạn biết liệu nó có thất bại / thành công hay không để bạn thực sự ngụ ý rằng trước đó, đó là lời giải thích hợp lý cho nó, bạn là gì? tại sao bạn tránh Should?
Eyal Solnik

51

Kent Beck gợi ý:

  • Một vật cố kiểm tra cho mỗi 'đơn vị' (lớp của chương trình của bạn). Kiểm tra đồ đạc là các lớp mình. Tên vật cố thử nghiệm phải là:

    [name of your 'unit']Tests
    
  • Các trường hợp thử nghiệm (các phương thức cố định kiểm tra) có các tên như:

    test[feature being tested]
    

Ví dụ: có lớp sau:

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

    // other methods and properties
}

Một vật cố thử nghiệm sẽ là:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}

4
Tôi muốn nhiều người sẽ làm theo các hướng dẫn này. Cách đây không lâu, tôi đã phải đổi tên hơn 20 phương thức thử nghiệm vì chúng có các tên như "ATest", "BasicTest" hoặc "ErrorTest".
Nêm

85
không phải tiền tố phương thức của 'test' trở nên dư thừa với hậu tố của lớp?
Gavin Miller

50
Hãy nhớ rằng khi Kent viết cuốn sách đó. Các thuộc tính không được phát minh. Do đó, tên Test trong tên phương thức được chỉ ra cho khung kiểm tra rằng phương thức đó là một thử nghiệm. Cũng có rất nhiều chuyện xảy ra kể từ năm 2002.
Thomas Jespersen

14
testCalculateAge ... đây là một tên vô nghĩa cho phương pháp thử nghiệm của bạn. "kiểm tra" là dự phòng (bạn có đặt tên cho tất cả các phương thức của mình bằng tiền tố "phương thức" không?). Phần còn lại của tên không có điều kiện đang thử nghiệm hoặc những gì đã được mong đợi. Là
CompateAge

1
Tôi muốn thêm rằng khi sử dụng chiến lược này, tài liệu được yêu cầu để chỉ định đầu ra dự kiến. Như một lưu ý phụ về tiền tố 'kiểm tra'; một số khung kiểm tra đơn vị yêu cầu các tiền tố hoặc hậu tố cụ thể để nhận ra các kiểm tra. Tiền tố các lớp trừu tượng với 'Tóm tắt' không được coi là dư thừa (vì nó tự ghi lại tài liệu), vậy tại sao không áp dụng tương tự với 'Kiểm tra'?
siebz0r

17

Tên lớp . Đối với tên của vật cố thử nghiệm, tôi thấy rằng "Thử nghiệm" khá phổ biến trong ngôn ngữ phổ biến ở nhiều miền. Ví dụ: trong một lĩnh vực kỹ thuật: StressTestvà trong một lĩnh vực mỹ phẩm : SkinTest. Xin lỗi vì không đồng ý với Kent, nhưng sử dụng "Thử nghiệm" trong đồ đạc thử nghiệm của tôi ( StressTestTest?) Là khó hiểu.

"Đơn vị" cũng được sử dụng rất nhiều trong các lĩnh vực. Ví dụ MeasurementUnit. Là một lớp được gọi là MeasurementUnitTestmột bài kiểm tra "Đo lường" hoặc "Đo lường"?

Do đó, tôi thích sử dụng tiền tố "Qa" cho tất cả các lớp kiểm tra của mình. Ví dụ QaSkinTestQaMeasurementUnit. Nó không bao giờ bị nhầm lẫn với các đối tượng miền và sử dụng tiền tố thay vì hậu tố có nghĩa là tất cả các thiết bị kiểm tra sống cùng nhau một cách trực quan (hữu ích nếu bạn có hàng giả hoặc các lớp hỗ trợ khác trong dự án thử nghiệm của bạn)

Không gian tên . Tôi làm việc trong C # và tôi giữ các lớp kiểm tra của mình trong cùng một không gian tên với lớp mà chúng đang kiểm tra. Nó thuận tiện hơn so với việc có các không gian tên thử nghiệm riêng biệt. Tất nhiên, các lớp kiểm tra là trong một dự án khác nhau.

Tên phương pháp thử . Tôi muốn đặt tên phương thức của mình là KhiXXX_ExpectYYY. Nó làm cho điều kiện tiên quyết rõ ràng và giúp với tài liệu tự động (a la TestDox). Điều này tương tự như lời khuyên trên blog thử nghiệm của Google, nhưng với nhiều điều kiện tiên quyết và kỳ vọng hơn. Ví dụ:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory

bạn đã nói về tên phương thức thử nghiệm và tên vật cố thử nghiệm. tên vật cố thử nghiệm được ánh xạ đến các lớp sản xuất. Nơi nào bạn viết tên phương thức sản xuất trong bài kiểm tra của bạn?
Ánh sáng

12

Tôi sử dụng khái niệm Cho-Khi-Sau đó . Hãy xem bài viết ngắn này http://ddingbaker.42dh.com/2009/05/28/given-when-then/ . Bài viết mô tả khái niệm này theo thuật ngữ của BDD, nhưng bạn cũng có thể sử dụng nó trong TDD mà không có bất kỳ thay đổi nào.


Cho-Khi-Sau đó giống như MethodName_Scenario_ExpectedBehavior, phải không?!
Ánh sáng

1
Không chính xác. Given_When_Then đề cập nhiều hơn đến: GivenAnEntity_WhenSomeActionHappens_ThatResultIsExpected Bài kiểm tra cần thể hiện ý chí để kiểm tra hành vi không phải là thực hiện .
plog17

1
"Đưa ra khi đó" thường được gọi là Gherkin. Đó là một DSL xuất phát từ các công cụ Cucumber, JBehave và Behat.
bytedev 30/03/2016

+1 đây là phương pháp tốt nhất imo. Việc tách riêng làm thế nào một phương thức làm một cái gì đó từ những gì bạn mong đợi là kết quả rất mạnh mẽ và tránh được rất nhiều vấn đề được mô tả trong các bình luận khác.
Lee


7

Tôi nghĩ một trong những điều quan trọng nhất là nhất quán trong quy ước đặt tên của bạn (và đồng ý với các thành viên khác trong nhóm của bạn). Nhiều lần tôi thấy vô số các quy ước khác nhau được sử dụng trong cùng một dự án.


7

Gần đây tôi đã đưa ra quy ước sau đây để đặt tên cho các bài kiểm tra của mình, các lớp của chúng và chứa các dự án để tối đa hóa mô tả của chúng:

Hãy nói rằng tôi đang thử nghiệm Settingslớp trong một dự án trong MyApp.Serializationkhông gian tên.

Đầu tiên tôi sẽ tạo một dự án thử nghiệm với MyApp.Serialization.Testskhông gian tên.

Trong dự án này và tất nhiên không gian tên tôi sẽ tạo một lớp có tên IfSettings(được lưu dưới dạng IfSinstall.cs ).

Hãy nói rằng tôi đang thử nghiệm SaveStrings()phương pháp. -> Tôi sẽ đặt tên cho bài kiểm tra CanSaveStrings().

Khi tôi chạy thử nghiệm này, nó sẽ hiển thị tiêu đề sau:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Tôi nghĩ rằng điều này cho tôi biết rất rõ, những gì nó đang thử nghiệm.

Tất nhiên điều hữu ích là trong tiếng Anh, danh từ "Tests" giống như động từ "tests".

Không có giới hạn cho sự sáng tạo của bạn trong việc đặt tên cho các bài kiểm tra, để chúng tôi có được các tiêu đề câu đầy đủ cho chúng.

Thông thường tên Test sẽ phải bắt đầu bằng một động từ.

Những ví dụ bao gồm:

  • Phát hiện (ví dụ DetectsInvalidUserInput)
  • Ném (ví dụ ThrowsOnNotFound)
  • Sẽ (ví dụ WillCloseTheDatabaseAfterTheTransaction)

Vân vân.

Một lựa chọn khác là sử dụng "cái đó" thay vì "nếu".

Cái sau giúp tôi tiết kiệm tổ hợp phím và mô tả chính xác hơn những gì tôi đang làm, vì tôi không biết, rằng hành vi được thử nghiệm có mặt, nhưng đang thử nghiệm nếu có.

[ Chỉnh sửa ]

Sau khi sử dụng quy ước đặt tên ở trên lâu hơn một chút, tôi đã thấy rằng tiền tố If có thể gây nhầm lẫn khi làm việc với các giao diện. Nó chỉ xảy ra như vậy, rằng lớp thử nghiệm IfSerializer.cs trông rất giống với giao diện ISerializer.cs trong "Tab mở tệp". Điều này có thể trở nên rất khó chịu khi chuyển đổi qua lại giữa các bài kiểm tra, lớp được kiểm tra và giao diện của nó. Kết quả là bây giờ tôi sẽ chọn That over If làm tiền tố.

Ngoài ra, bây giờ tôi sử dụng - chỉ cho các phương thức trong các lớp thử nghiệm của mình vì nó không được coi là thực tiễn tốt nhất ở bất kỳ nơi nào khác - "_" để phân tách các từ trong tên phương thức thử nghiệm của tôi như trong:

[Test] public void detects_invalid_User_Input()

Tôi thấy điều này để dễ đọc hơn.

[ Kết thúc chỉnh sửa ]

Tôi hy vọng điều này sẽ sinh ra thêm một số ý tưởng, vì tôi xem xét việc đặt tên các bài kiểm tra có tầm quan trọng lớn vì nó có thể giúp bạn tiết kiệm rất nhiều thời gian mà nếu không đã cố gắng để hiểu các bài kiểm tra đang làm gì (ví dụ như sau khi tiếp tục một dự án sau khi gián đoạn kéo dài) .


2

Trong VS + NUnit, tôi thường tạo các thư mục trong dự án của mình để nhóm các kiểm tra chức năng lại với nhau. Sau đó, tôi tạo các lớp vật cố thử nghiệm đơn vị và đặt tên chúng theo loại chức năng tôi đang thử nghiệm. Các phương thức [Kiểm tra] được đặt tên dọc theo dòng 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

Tôi nên thêm rằng việc giữ các kiểm tra của bạn trong cùng một gói nhưng trong một thư mục song song với nguồn được kiểm tra sẽ loại bỏ sự phình to của mã một khi bạn sẵn sàng triển khai nó mà không phải thực hiện một loạt các mẫu loại trừ.

Cá nhân tôi thích các thực tiễn tốt nhất được mô tả trong "Hướng dẫn bỏ túi JUnit" ... thật khó để đánh bại một cuốn sách được viết bởi đồng tác giả của JUnit!


3
Đừng tin điều này thực sự trả lời câu hỏi trong tầm tay - bạn có thể thực hiện chỉnh sửa và điều chỉnh Hướng dẫn bỏ túi JUnit không? Cảm ơn!
Nate-Wilkins

0

tên của trường hợp thử nghiệm cho lớp Foo phải là FooTestCase hoặc một cái gì đó tương tự (FooIntegrationTestCase hoặc FooAcceptanceTestCase) - vì đây là trường hợp thử nghiệm. xem http: // xunitpotypes.com/ để biết một số quy ước đặt tên tiêu chuẩn như thử nghiệm, trường hợp thử nghiệm, vật cố thử nghiệm, phương pháp thử nghiệm, v.v.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.