2008-10-29 48 views
124

Cách tốt nhất để kiểm tra đơn vị một phương pháp không trả lại bất cứ điều gì là gì? Cụ thể trong C#.Đơn vị kiểm tra phương pháp void?

Điều tôi thực sự cố gắng kiểm tra là một phương thức lấy tệp nhật ký và phân tích cú pháp đó cho các chuỗi cụ thể. Các chuỗi này sau đó được chèn vào cơ sở dữ liệu. Không có gì đã không được thực hiện trước đây nhưng là VERY mới để TDD Tôi tự hỏi nếu nó có thể kiểm tra này hoặc là nó một cái gì đó mà không thực sự được thử nghiệm.

+33

Vui lòng không sử dụng cụm từ "TDD" nếu đó không phải là những gì bạn đang làm. Bạn đang thực hiện Kiểm thử Đơn vị, không phải là TDD. Nếu bạn đang làm TDD, bạn sẽ không bao giờ có một câu hỏi như "làm thế nào để kiểm tra một phương pháp." Bài kiểm tra sẽ tồn tại trước tiên, và sau đó câu hỏi sẽ là, "làm thế nào để có được bài kiểm tra này để vượt qua?" Nhưng nếu bạn đang làm TDD, mã của bạn sẽ được viết cho thử nghiệm (không phải là cách khác xung quanh), và bạn về cơ bản sẽ trả lời câu hỏi của riêng bạn. Mã của bạn sẽ được định dạng khác với kết quả của TDD và vấn đề này sẽ không bao giờ xảy ra. Chỉ cần làm rõ. – Suamere

Trả lời

110

Nếu một phương pháp không trả lại bất cứ điều gì, đó là một trong hai điều sau đây

  • bắt buộc - Bạn đang hoặc yêu cầu đối tượng để làm điều gì đó cho chính nó .. ví dụ như thay đổi trạng thái (không mong đợi bất kỳ xác nhận .. giả định rằng nó sẽ được thực hiện)
  • thông tin - chỉ cần thông báo cho ai đó rằng điều gì đó đã xảy ra (không mong đợi hành động hoặc phản hồi) tương ứng.

Phương pháp bắt buộc - bạn có thể xác minh xem tác vụ có thực sự được thực hiện hay không.Xác minh nếu thay đổi trạng thái thực sự diễn ra. ví dụ.

void DeductFromBalance(dAmount) 

thể được kiểm tra bằng cách kiểm tra nếu bài cân bằng thông điệp này là thực sự thấp hơn giá trị ban đầu bằng dAmount

phương pháp Informational - rất hiếm khi một thành viên của giao diện nào của đối tượng ... do đó thường không được kiểm tra đơn vị. Tuy nhiên, nếu bạn phải, Bạn có thể xác minh xem việc xử lý được thực hiện trên một thông báo có diễn ra không. ví dụ.

void OnAccountDebit(dAmount) // emails account holder with info 

thể được kiểm tra bằng cách kiểm tra nếu email này đang được gửi

bài viết chi tiết hơn về phương pháp thực tế của bạn và mọi người sẽ có thể trả lời tốt hơn.
Cập nhật: Phương pháp của bạn đang thực hiện 2 việc. Tôi thực sự chia nó thành hai phương pháp mà bây giờ có thể được kiểm tra độc lập.

string[] ExamineLogFileForX(string sFileName); 
void InsertStringsIntoDatabase(string[]); 

Chuỗi [] có thể dễ dàng được xác minh bằng cách cung cấp phương thức đầu tiên có tệp giả và chuỗi dự kiến. Thứ hai là hơi khó khăn .. bạn có thể sử dụng một Mock (google hoặc tìm kiếm stackoverflow trên mocking khuôn khổ) để bắt chước DB hoặc nhấn DB thực tế và xác minh nếu các chuỗi đã được chèn vào đúng vị trí. Kiểm tra this thread để biết một số sách hay ... Tôi sẽ recomment Pragmatic Unit Testing nếu bạn đang ở trong một cuộc khủng hoảng.
Trong mã, mã sẽ được sử dụng như

InsertStringsIntoDatabase(ExamineLogFileForX("c:\OMG.log")); 
+0

thông tin chi tiết ở trên – jdiaz

+1

hey gishu, câu trả lời hay. Ví dụ bạn đưa ra ... không phải là họ kiểm tra tích hợp nhiều hơn ...? và nếu như vậy, câu hỏi vẫn còn, làm thế nào để thực sự kiểm tra phương pháp Void .... có lẽ nó không thể? – andy

+1

@andy - phụ thuộc vào định nghĩa của bạn về 'kiểm tra tích hợp'. Phương pháp bắt buộc thường thay đổi trạng thái, vì vậy bạn có thể được xác minh bằng một phép thử đơn vị để thẩm vấn trạng thái của đối tượng. Các phương thức thông tin có thể được xác minh bằng một bài kiểm tra đơn vị cắm vào một người nghe/cộng tác giả để đảm bảo rằng đối tượng thử nghiệm đưa ra thông báo đúng. Tôi nghĩ cả hai có thể được kiểm tra hợp lý thông qua các bài kiểm tra đơn vị. – Gishu

5

nó sẽ có một số ảnh hưởng đến truy vấn đối tượng .... cho kết quả của hiệu ứng. Nếu nó không có hiệu lực có thể nhìn thấy thử nghiệm đơn vị không có giá trị của nó!

-1

Bạn cũng nên kiểm tra xem phương thức có ném ngoại lệ hay không.

+5

Điều này là khá trần xương cho một câu trả lời. Có lẽ một bình luận thay thế? –

2

Phụ thuộc vào những gì nó đang làm. Nếu nó có các tham số, chuyển vào các mocks mà bạn có thể hỏi sau này nếu chúng đã được gọi với tập các tham số đúng.

+0

Đồng ý - xác minh hành vi của các mocks thử nghiệm phương pháp sẽ là một cách. –

22

Như mọi khi: hãy thử nghiệm phương pháp được cho là phải làm!

Nếu nó thay đổi trạng thái toàn cầu (uuh, mã mùi!) Ở đâu đó?

Nó có nên gọi vào giao diện không?

Có nên ném ngoại lệ khi được gọi với thông số sai không?

Nếu nó không ném ngoại lệ khi được gọi với các thông số đúng?

Có nên ...?

4

Có lẽ phương thức thực hiện điều gì đó và không đơn giản quay trở lại?

Giả sử đây là trường hợp, sau đó:

  1. Nếu nó đổi trạng thái của nó là chủ sở hữu đối tượng, sau đó bạn nên kiểm tra rằng nhà nước đã thay đổi một cách chính xác.
  2. Nếu phải mất một số đối tượng làm tham số và sửa đổi đối tượng đó, thì bạn nên kiểm tra đối tượng được sửa đổi chính xác.
  3. Nếu nó ném ngoại lệ là một số trường hợp nhất định, hãy kiểm tra xem các ngoại lệ đó có được ném đúng cách không.
  4. Nếu hành vi của nó thay đổi dựa trên trạng thái của đối tượng riêng hoặc đối tượng khác, hãy đặt trước trạng thái và kiểm tra phương pháp có Ithrough chính xác trong ba phương pháp thử nghiệm ở trên).

Nếu bạn cho chúng tôi biết phương pháp làm gì, tôi có thể cụ thể hơn.

45

Kiểm tra tác dụng phụ của nó. Điều này bao gồm:

  • Nó có ném bất kỳ ngoại lệ nào không? Nếu cần, hãy thử một số trường hợp góc có thể nếu bạn không cẩn thận - đối số rỗng là điều hiển nhiên nhất.)
  • Liệu nó có độc đáo với các thông số của nó không? (Nếu chúng có thể thay đổi, nó có làm thay đổi chúng khi nó không nên và ngược lại không?)
  • Nó có ảnh hưởng đúng đến trạng thái của đối tượng/kiểu bạn đang gọi nó không?

Tất nhiên, có giới hạn về cách nhiều bạn có thể kiểm tra. Bạn thường không thể thử nghiệm với mọi đầu vào có thể, ví dụ. Kiểm tra thực tế - đủ để cung cấp cho bạn sự tự tin rằng mã của bạn được thiết kế phù hợp và được triển khai chính xác và đủ để hoạt động như tài liệu bổ sung cho những gì người gọi có thể mong đợi.

3

Sử dụng Rhino Mocks để đặt những lời gọi, hành động và ngoại lệ nào có thể xảy ra. Giả sử bạn có thể giả lập hoặc tách ra các phần của phương pháp của bạn. Thật khó để biết mà không biết một số chi tiết cụ thể ở đây về phương pháp, hoặc thậm chí bối cảnh.

+1

Câu trả lời cho cách kiểm tra đơn vị không bao giờ nên là để có được công cụ của bên thứ ba thực hiện nó cho bạn. Mặc dù, khi một người biết làm thế nào để kiểm tra đơn vị, sử dụng một công cụ của bên thứ ba để làm cho nó dễ dàng hơn là chấp nhận được. – Suamere

5

Loại trả lại không có giá trị/Chương trình con là tin cũ. Tôi đã không thực hiện một loại trở lại Void (Trừ khi tôi đã được cực kỳ lười biếng) trong như 8 năm (Từ thời điểm câu trả lời này, vì vậy chỉ cần một chút trước khi câu hỏi này được hỏi).

Thay vì một phương pháp như:

public void SendEmailToCustomer() 

Thực hiện một phương pháp mà sau int của Microsoft.TryParse() mô hình:

public bool TrySendEmailToCustomer() 

Có lẽ không có bất kỳ thông tin phương pháp của bạn cần phải quay trở lại để sử dụng trong dài hạn, nhưng trở về trạng thái của phương pháp này sau khi nó thực hiện công việc của mình là một sử dụng rất lớn đến người gọi.

Ngoài ra, bool không phải là loại trạng thái duy nhất. Có một số lần khi một chương trình con được tạo trước đó thực sự có thể trả lại ba hoặc nhiều trạng thái khác nhau (Tốt, Bình thường, Xấu, v.v.). Trong những trường hợp đó, bạn chỉ cần sử dụng

public StateEnum TrySendEmailToCustomer() 

Tuy nhiên, trong khi Try-Paradigm trả lời một chút câu hỏi này về cách kiểm tra khoảng trống, cũng có những cân nhắc khác. Ví dụ, trong/sau một chu kỳ "TDD", bạn sẽ "Refactoring" và nhận thấy bạn đang làm hai việc với phương pháp của bạn ... do đó phá vỡ "Nguyên tắc trách nhiệm duy nhất". Vì vậy, cần được chăm sóc đầu tiên. Thứ hai, bạn có thể đã idenetified một phụ thuộc ... bạn đang chạm vào "Persistent" dữ liệu.

Nếu bạn đang thực hiện công cụ truy cập dữ liệu trong phương pháp được đề cập, bạn cần phải cấu trúc lại thành kiến ​​trúc n-tier'd hoặc n-layer'd. Nhưng chúng ta có thể giả định rằng khi bạn nói "Các chuỗi sau đó được chèn vào cơ sở dữ liệu", bạn thực sự có nghĩa là bạn đang gọi một lớp logic nghiệp vụ hoặc một cái gì đó. Ya, chúng tôi sẽ giả định điều đó.

Khi đối tượng của bạn được khởi tạo, bây giờ bạn hiểu rằng đối tượng của bạn có phụ thuộc. Đây là khi bạn cần phải quyết định xem bạn sẽ làm Dependency Injection trên Object hay trên phương thức. Điều đó có nghĩa Constructor của bạn hoặc phương pháp-in-câu hỏi cần có một thông số mới:

public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert) 

Bây giờ bạn có thể chấp nhận một giao diện của đối tượng kinh doanh/cấp dữ liệu của bạn, bạn có thể thử nó ra trong đơn vị xét nghiệm và không có phụ thuộc hoặc sợ thử nghiệm tích hợp "Tình cờ".

Vì vậy, trong mã trực tiếp, bạn chuyển vào đối tượng REAL IBusinessDataEtc. Nhưng trong Thử nghiệm Đơn vị của bạn, bạn chuyển vào đối tượng MOCK IBusinessDataEtc. Trong Mock đó, bạn có thể bao gồm các thuộc tính không giao diện như int XMethodWasCalledCount hoặc một cái gì đó có (các) trạng thái được cập nhật khi các phương thức giao diện được gọi.

Vì vậy, Bài kiểm tra đơn vị của bạn sẽ đi qua (các) Phương pháp của bạn -In-Question, thực hiện bất kỳ logic nào họ có và gọi một hoặc hai hoặc một bộ phương pháp đã chọn trong đối tượng IBusinessDataEtc của bạn. Khi bạn làm Assertions của bạn ở phần cuối của bài kiểm tra Unit của bạn, bạn có một vài thứ để kiểm tra ngay bây giờ.

  1. Trạng thái của "Chương trình con" hiện là phương pháp Try-Paradigm.
  2. Trạng thái của đối tượng Mock IBusinessDataEtc của bạn.

Để biết thêm thông tin về phụ thuộc Tiêm ý tưởng về cấp xây dựng ... khi chúng liên quan đến Kiểm tra đơn vị ... hãy xem xét các mẫu thiết kế Builder. Nó bổ sung thêm một giao diện và lớp cho mỗi giao diện hiện tại/lớp bạn có, nhưng chúng rất nhỏ và cung cấp chức năng HUGE tăng để kiểm tra Đơn vị tốt hơn.

2

Hãy thử điều này:

[TestMethod] 
public void TestSomething() 
{ 
    try 
    { 
     YourMethodCall(); 
     Assert.IsTrue(true); 
    } 
    catch { 
     Assert.IsTrue(false); 
    } 
} 
+1

Điều này không cần thiết nhưng có thể được thực hiện như vậy –

+0

Chào mừng bạn đến với StackOverflow! Vui lòng xem xét thêm một số giải thích cho mã của bạn. Cảm ơn bạn. – Aurasphere

+1

['ExpectedAttribute'] (https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.expectedexceptionattribute.aspx) được thiết kế để làm cho bài kiểm tra này rõ ràng hơn. –

-1

gì bao giờ dụ bạn đang sử dụng để gọi phương thức bãi bỏ, Bạn chỉ có thể sử dụng, Verfiy

Ví dụ:

Trong trường hợp của tôi _Log của nó là ví dụ và LogMessage là phương pháp được kiểm tra:

try 
{ 
    this._log.Verify(x => x.LogMessage(Logger.WillisLogLevel.Info, Logger.WillisLogger.Usage, "Created the Student with name as"), "Failure"); 
} 
Catch 
{ 
    Assert.IsFalse(ex is Moq.MockException); 
} 

Verify ném một ngoại lệ do thất bại của phương pháp thử nghiệm sẽ thất bại?

Các vấn đề liên quan