2009-07-02 5 views
5

Vì vậy, tôi có một lớp học với một phương pháp như sau:Làm thế nào để đơn vị kiểm tra một chi tiết thực hiện như bộ nhớ đệm

public class SomeClass 
{ 
    ... 

    private SomeDependency m_dependency; 

    public int DoStuff() 
    { 
     int result = 0; 
     ... 
     int someValue = m_dependency.GrabValue(); 
     ... 
     return result; 
    } 
} 

Và tôi đã quyết định rằng thay vì gọi m_dependency.GrabValue() mỗi lần, tôi thực sự muốn bộ nhớ cache giá trị trong bộ nhớ (tức là trong lớp này) vì chúng ta sẽ nhận được cùng một giá trị mỗi lần (phụ thuộc sẽ tắt và lấy một số dữ liệu từ một bảng mà hầu như không bao giờ thay đổi).

Tôi đã gặp sự cố tuy nhiên cố mô tả hành vi mới này trong thử nghiệm đơn vị. Tôi đã thử những điều sau (Tôi đang sử dụng NUnit với RhinoMocks):

[Test] 
public void CacheThatValue() 
{ 
    var depend = MockRepository.GeneraMock<SomeDependency>(); 

    depend.Expect(d => d.GrabValue()).Repeat.Once().Return(1); 

    var sut = new SomeCLass(depend); 
    int result = sut.DoStuff(); 
    result = sut.DoStuff(); 
    depend.VerifyAllExpectations(); 
} 

Tuy nhiên, điều này không hiệu quả; kiểm tra này vượt qua ngay cả khi không giới thiệu bất kỳ thay đổi nào đối với chức năng. Tôi đang làm gì sai?

+2

Xin lỗi vì đã đặt câu hỏi, nhưng tại sao lại kiểm tra điều gì đó là chi tiết triển khai? – Robert

Trả lời

5

Tôi thấy bộ nhớ đệm là trực giao với Nội dung (Thực hiện). Tôi sẽ tìm một cách để kéo logic caching ra ngoài phương thức, hoặc bằng cách thay đổi SomeDependency hoặc gói nó bằng cách nào đó (bây giờ tôi có một ý tưởng tuyệt vời cho một lớp đệm dựa trên các biểu thức lambda - yum).

Bằng cách đó, các thử nghiệm của bạn cho DoStuff không cần phải thay đổi, bạn chỉ cần đảm bảo chúng hoạt động với trình bao bọc mới. Sau đó, bạn có thể kiểm tra chức năng bộ nhớ đệm của SomeDependency, hoặc trình bao bọc của nó, độc lập. Với mã được cấu trúc tốt đặt một lớp đệm vào đúng chỗ nên khá dễ dàng và không phải sự phụ thuộc của bạn cũng như sự thực thi của bạn cũng không nên biết sự khác biệt.

Kiểm tra đơn vị không nên thử nghiệm triển khai, họ nên kiểm tra hành vi. Đồng thời, đối tượng được thử nghiệm phải có một tập hợp hành vi được xác định hẹp.

Để trả lời câu hỏi của bạn, bạn đang sử dụng Mock động và hành vi mặc định là cho phép bất kỳ cuộc gọi nào không được định cấu hình. Các cuộc gọi bổ sung chỉ trở lại "0". Bạn cần thiết lập kỳ vọng rằng không có thêm cuộc gọi nào được thực hiện trên sự phụ thuộc:

depend.Expect(d => d.GrabValue()).Repeat.Once().Return(1); 
depend.Expect(d => d.GrabValue()).Repeat.Never(); 

Bạn có thể cần phải nhập chế độ ghi lại/phát lại để hoạt động bình thường.

+0

Điểm tốt: "Bài kiểm tra đơn vị không nên thử nghiệm triển khai, họ nên kiểm tra hành vi. Đồng thời, đối tượng được kiểm tra phải có tập hợp hành vi được xác định hẹp". Điều này trả lời câu hỏi của tôi (cũng như bình luận của Robert cho câu hỏi của tôi) – jpoh

4

Điều này có vẻ giống như trường hợp "kiểm tra lái xe thiết kế". Nếu bộ nhớ đệm là một chi tiết thực hiện của SubDependency - và do đó không thể được kiểm tra trực tiếp - thì có thể một số chức năng của nó (cụ thể là hành vi đệm của nó) cần phải được phơi bày - và vì nó không tự nhiên để lộ nó trong SubDependency, cần phải tiếp xúc trong lớp khác (hãy gọi nó là "Cache"). Trong Cache, tất nhiên, hành vi là hợp đồng - công khai, và do đó có thể kiểm chứng được.

Vì vậy, các xét nghiệm - và mùi - đang cho chúng ta biết chúng ta cần một lớp mới. Thiết kế thử nghiệm. Nó không tuyệt vời sao?