2010-02-18 27 views
9

Tôi thực sự quen với TDD gần đây, và sau khi đọc cuốn sách của Kent Beck về Phát triển thử nghiệm, tôi vẫn có nhiều câu hỏi xung quanh thiết kế thử nghiệm trong tâm trí của tôi.TDD Mocking - Đang xác định thử nghiệm đối tượng mô phỏng hộp màu trắng?

Một trong những vấn đề tôi hiện đang gặp là sử dụng các đối tượng Mock. Thực hiện dưới đây rất đơn giản để tạo báo cáo:

public string MakeFinancialReport() 
{ 
    return sys1.GetData() + sys2.GetData() + sys3.GetData(); 
} 

Báo cáo phải chứa tiêu đề, nội dung và chân trang. Vì vậy, một thử nghiệm nhanh để xem những danh hiệu tồn tại trong báo cáo:

public void TestReport() 
{ 
    string report = MakeFinancialReport(); 
    Assert.IsTrue(report.Contains("[Title]") && report.Contains("[Body]") && report.Contains("[Footer]")); 
} 

Để cô lập phương pháp này, tôi đoán tôi sẽ chế giễu đi những sys1, sys2 và sys3 cuộc gọi. Bây giờ, nếu tất cả chúng đều là mocks, thì tôi có gì để kiểm tra? Ngoài ra, khi tôi chế nhạo chúng, tại sao tôi phải nói với các đối tượng giả định rằng chúng sẽ được gọi là một lần và trả về X vv. Nó không chỉ là một thử nghiệm hộp đen và MakeFinancialReport có thể thực hiện nhiều cuộc gọi như nó muốn xây dựng báo cáo?

Tôi đang bối rối với một vấn đề nhỏ như vậy, tôi không chắc chắn những gì tôi đang thiếu. Tôi thấy Mocking như lấy đi mã có thể thử nghiệm, và đối với hầu hết các phương pháp đơn giản, những gì còn lại để kiểm tra là không hữu ích cả.

Trả lời

2

Bạn chỉ nên sử dụng các đối tượng giả khi chúng hữu ích. Nếu MakeFinancialReport, sys1, sys2sys3 tất cả đều có logic phức tạp trong chúng, thì bạn muốn kiểm tra từng loại một cách độc lập. Bằng cách đưa ra các phiên bản giả của ba đối tượng sysX đến MakeFinancialReport, bạn loại bỏ sự phức tạp của chúng và chỉ cần kiểm tra MakeFinancialReport.

Các đối tượng giả đặc biệt hữu ích khi bạn muốn kiểm tra các điều kiện lỗi và xử lý ngoại lệ, bởi vì khó có thể buộc ngoại lệ từ đối tượng thực.

Khi bạn nói về việc không phải đặt kỳ vọng rõ ràng và giá trị trả về, đó là khái niệm liên quan được gọi là khai báo. Bạn có thể tìm thấy "Mocks Aren't Stubs" của Martin Fowler "hữu ích.

Cuốn sách của Kent Beck là một phần giới thiệu tuyệt vời, nhưng nếu bạn đang tìm kiếm thêm chi tiết, tôi khuyên bạn nên xem số xUnit Patterns book. Ví dụ: phần này có một phần trên mock objects, cũng như danh mục chung hơn là test doubles.

+1

Hmm, sau đó tôi nghĩ rằng tôi thiếu thiết kế thử nghiệm hiệu trưởng ở đâu đó. Tôi nghĩ thử nghiệm đơn vị là kiểm tra một phương pháp, một đoạn mã rời rạc nhỏ, không phải bất kỳ đối tượng cộng tác nào của nó. Các đối tượng cộng tác trong trường hợp này, sys1, sys2 và sys3, mỗi đối tượng đều có các bài kiểm tra đơn vị riêng của họ được bao gồm trong các bài kiểm tra đơn vị riêng biệt. Bài viết của Martin Fowler tôi đã đọc nhiều lần và từ những gì tôi có thể lấy từ sự khác biệt của Mocks và Stubs là sự khác biệt giữa kiểm tra trạng thái và hành vi. – Martin

+0

Tôi vẫn cần phải hiểu rằng tại sao chúng ta sử dụng chúng là vì chúng ta đang cố gắng di chuyển sự phức tạp của mã gọi bên ngoài một phương thức/đơn vị để chúng ta có thể tập trung vào hành vi của một phương pháp. Vì vậy, trong trường hợp này, chính xác những gì còn lại trong phương thức eMakeFinancialReport() nếu chúng ta lấy đi 3 cuộc gọi hệ thống thông qua mocks? – Martin

+2

Trong ví dụ của bạn, @Martin, tất cả những gì còn lại là nối chuỗi. Đó không phải là nhiều để kiểm tra. Nếu không có gì để kiểm tra, thì đó là một mùi mã sẽ thúc đẩy bạn hướng tới việc tái cấu trúc "Inline Method". Có lẽ bạn nên tìm một ví dụ tốt hơn. –

3

Vì nó đứng, MakeFinancialReport hầu như không làm gì ngoài việc tương tác với các cộng tác viên thú vị và có lẽ không đáng thử nghiệm đơn vị.

Nếu tôi đã viết bất kỳ bài kiểm tra đơn vị nào cho phương pháp đó, tôi có thể chỉ xác minh rằng phương pháp làm những gì tôi mong đợi khi các cộng tác viên của nó trả về null, chủ yếu để ghi lại hành vi dự kiến ​​(hoặc giúp tôi quyết định hành vi dự kiến ​​nếu Tôi làm điều đó trước). Hiện tại phương pháp này sẽ không thành công. Điều đó có thể tốt, nhưng đáng xem xét liệu bạn có muốn coi null là chuỗi trống không - và các bài kiểm tra đơn vị chứng minh rằng bất kỳ hành vi nào bạn quyết định là cố ý.

"Đang chỉ định thử nghiệm đối tượng thử nghiệm hộp màu trắng?" Tuyệt đối - nếu lớp học của bạn có một sự phụ thuộc mà bạn đang chế nhạo, bạn đang buộc thử nghiệm của bạn với sự phụ thuộc đó. Nhưng thử nghiệm hộp trắng có ưu điểm của nó. Không phải tất cả tương tác của cộng tác viên đều tầm thường như những người trong ví dụ của bạn.

0

Tôi nghĩ một trong những vấn đề là thử nghiệm của bạn trộn lẫn các trách nhiệm từ sys1, sys2 và sys3 với phương thức TestReport.Dường như với tôi rằng những gì bạn nên tách các xét nghiệm của mình thành 2 phần:

1) MakeFinancialReport() trả về kết nối của sys1, sys2, sys3. Ở đó bạn có thể còn sơ khai sys1, vv ..., với một cái gì đó dọc theo dòng của

var sys1 =MockRepository.GenerateStub<ISys>(); 
sys1.Expect(s=>s.GetData()).Return("Part 1"); 
// etc... for sys2, sys3 var 
reportMaker = new ReportMaker(sys1,sys2, sys3); 
Assert.AreEqual("Part 1" + "Part 2" + "Part 3", reportMaker.MakeFinancialReport(); 

Lớp sở hữu phương pháp MakeFinancialReport() không nên quan tâm hoặc biết những gì các lớp sys đang làm. Họ có thể trả lại bất kỳ lớp học nào - MakeFinancialReport() chỉ cần ghép nối, đó là những gì bạn nên kiểm tra (nếu bạn cho là nó đáng giá).

2) Kiểm tra phương thức GetData() từ giao diện sys1, sys2, sys3 triển khai. Đây có thể là nơi bạn sẽ kiểm tra trong trường hợp nào bạn sẽ thấy "Nội dung", "Tiêu đề", v.v ...
Việc đặt cọc có thể quá mức ở đây, nhưng những gì bạn mua là một sự khởi đầu giá rẻ 3 trường hợp sys), và phân tách rõ ràng những gì sys làm, và những gì MakeFinancialReport làm.

Ngoài ra, nó có thể là do ngôn ngữ bạn đang sử dụng, nhưng thật đáng ngạc nhiên là bài kiểm tra của bạn không bắt đầu với sự khởi tạo của lớp sở hữu MakeFinancialReport().

4

Martin, tôi nghĩ bạn nên sử dụng mocks cho sys1-3, nhưng chúng chỉ cần đủ đơn giản để trả về một chuỗi ký tự đơn.

Điều này có nghĩa thử nghiệm của bạn sẽ giống như thế:

public void TestReport() 
{ 
    // Setup mocks for sys1-3 
    string report = MakeFinancialReport(); 
    Assert.IsTrue(report.equals("abc")); 
} 

Điều này cho thấy MakeFinancialReport có các thuộc tính mà nó gọi GetData() từ sys1-3 nó concatenates kết quả theo thứ tự đặc biệt này.

+0

+1 Câu trả lời hay. Nếu tất cả mọi người sử dụng mocks này rõ ràng, họ sẽ được chấp nhận rộng rãi hơn nhiều. –

+0

@quamrana Chúng ta có đang thử nghiệm hộp trắng ở đây không? Sau khi tất cả, chúng ta cần phải biết việc thực hiện 'MakeFinancialReport' để viết bài kiểm tra này. Nếu chúng ta cần thêm 'sys4' một ngày, chúng ta sẽ phải sửa đổi cả hai' MakeFinancialReport' và test. Điều này có nghĩa là sử dụng mô hình làm tổn thương tính linh hoạt? – satoru

+0

@ Satoru.Logic Chúng tôi không làm thử nghiệm hộp màu trắng ở đây - Xem thẻ 'tdd'. Nếu chúng ta viết một 'sys4' một ngày thì chúng ta sẽ cần một thử nghiệm mới để kiểm tra một sys4 thực và sửa đổi thử nghiệm của tôi ở trên để kiểm tra rằng' MakeFinancialReport' làm một điều mới. Các trách nhiệm khác nhau là trong các bài kiểm tra khác nhau. – quamrana

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