7

Tôi đang sử dụng Microsoft Unit Test và đã điều sau đây:Đơn vị có đời phạm vi được xử lý bởi IoC container

public class AccountCommandHandlers : 
    Handler<CreateAccountCommand>, 
    Handler<CloseAccountCommand> 
{ 
    public bool CreateAccountCommandWasCalled = false; 
    public bool CloseAccountCommandWasCalled = false; 

    public void Handle(CreateAccountCommand command) 
    { 
     CreateAccountCommandWasCalled = true; 
    } 

    public void Handle(CloseAccountCommand command) 
    { 
     CloseAccountCommandWasCalled = true; 
    } 
} 

[TestMethod] 
public void CanRaiseInternalHandlers() 
{ 
    var iocContainer = SimpleInjectorWiringForMembus.Instance; 
    iocContainer.Bootstrap(
     AppDomain.CurrentDomain.GetAssemblies()); 

    var membus = MembusWiring.Instance; 
    membus.Bootstrap(); 

    membus.Bus.Publish(new CreateAccountCommand() { Id = 100 }); 
    membus.Bus.Publish(new CloseAccountCommand() { Id = 100 }); 
} 

Tôi đang sử dụng một container IoC (Simple Injector) mà xử lý phạm vi tuổi thọ của các đối tượng. Membus nối các lệnh để xử lý lệnh và giải quyết thông qua vùng chứa IoC.

Mã trên chạy và hoạt động và trình xử lý lệnh đặt các biến cục bộ của họ thành true.

Tuy nhiên, vì Injector đơn giản xử lý phạm vi thời gian, tôi không thể yêu cầu Simple Injector cho đối tượng AccountCommandHandler vì nó sẽ trả về một đối tượng mới với CreateAccountCommandWasCalled được đặt thành false.

Làm mới để kiểm tra đơn vị điều gì sẽ là một cách mạnh mẽ hơn để kiểm tra khác hơn là thiết lập CreateAccountCommandWasCalled làm biến tĩnh?

Trả lời

5

Như những người khác đã đề cập, bạn đang thực sự chạy thử nghiệm tích hợp. Tuy nhiên, đây không phải là vấn đề. Kiểm tra tích hợp phù hợp để kiểm tra cài đặt IoC của bạn và để đảm bảo rằng các phần khác nhau của ứng dụng của bạn hoạt động cùng nhau.

Tuy nhiên, với thử nghiệm tích hợp, bạn không nên sử dụng các đối tượng giả hoặc sơ đồ. Mocks và cuống có sử dụng của họ trong thử nghiệm đơn vị. Một bài kiểm tra đơn vị là tất cả về việc kiểm tra phần nhỏ nhất có thể của mã của bạn. Trong một thử nghiệm đơn vị, bạn sử dụng mocks để kiểm soát hành vi của tất cả các phụ thuộc mà lớp của bạn có. Tôi đã viết một blog một năm trước đây đưa ra một giới thiệu về sự khác biệt giữa các bài kiểm tra tích hợp và đơn vị và cách sử dụng chế nhạo trong các bài kiểm tra của bạn.

Trong trường hợp của bạn, tôi sẽ không sử dụng vùng chứa IoC với cấu hình sản xuất để thiết lập các thử nghiệm đơn vị của bạn. Thay vào đó, tôi sẽ chuyển sang tạo thủ công đối tượng của bạn trong các thử nghiệm của bạn và sử dụng công cụ chế nhạo như Moq để kiểm soát các phụ thuộc.

Nhưng đây cũng là thứ có thể được tự động hóa. Một công cụ tuyệt vời là AutoFixture. 'Lịch thi đấu' đề cập đến đường cơ sở bạn cần để chạy thử nghiệm của mình. Điều này có thể là một số dữ liệu mẫu, các mocks và stubs bạn cần và mã thiết lập khác.

Mark Seemann (nhà phát triển đằng sau AutoFixture) đã viết một blog hay cách đây một vài tuần về cách sử dụng AutoFixture cùng với một IoC là Auto-mocking Container. Tôi sẽ khuyên bạn nên sử dụng một cái gì đó như thế này để cấu trúc các bài kiểm tra đơn vị của bạn.

5

Dưới đây là một "triết học" Câu trả lời nhiều câu hỏi của bạn :-)

Khuyến cáo của tôi sẽ là không sử dụng các container IOC trong thử nghiệm của bạn ở tất cả, nếu có thể!

Lý do cơ bản của tôi là bạn cần kiểm tra của mình để có toàn quyền kiểm soát ngữ cảnh của thử nghiệm và IOC có thể lấy đi một số kiểm soát này. IMO, các xét nghiệm đơn vị nên được tập trung, nhỏ và có thể dự đoán được càng tốt!

Xem xét việc gửi các đối tượng giả vào lớp của bạn đang được kiểm tra, thay vì các lớp thực tế.

Nếu lớp học của bạn cần có một thể hiện nội bộ của một thùng chứa IOC, hãy đưa yếu tố này ra khỏi lớp học thành một "bộ điều khiển" của một số loại.

Bạn có thể thực hiện việc này theo nhiều cách, tôi thích sử dụng khung như Rhino Mocks.

Bằng cách này, bạn thực sự sẽ loại bỏ "vòng đời" được cung cấp bởi IOC vào thời gian chạy, trong bài kiểm tra "thiết lập" của bạn.

Vì vậy, kiểm tra phải có toàn quyền kiểm soát (thông qua chế nhạo và rình mò) khi đối tượng được tạo hoặc hủy, sử dụng một khung như Rhino.

Bạn có thể giả lập IOC, nếu điều này thậm chí còn cần thiết. Là một lưu ý phụ, một trong những lợi ích của một container IOC được thiết kế tốt là nó sẽ làm cho việc kiểm thử đơn vị dễ dàng hơn - bởi vì nó sẽ ngăn cản các lớp dựa vào "các thể hiện cụ thể" thực tế của các lớp, và khuyến khích sử dụng hoán đổi cho nhau giao diện thay thế.

Bạn nên thử dựa vào thời gian chạy trên vùng chứa IOC cung cấp việc triển khai cụ thể các giao diện mà bạn đã thiết kế chống lại.

Lưu ý rằng điều quan trọng cũng thường là phải làm rõ về những gì bạn đang thực sự thử nghiệm. Các bài kiểm tra đơn vị thường tập trung vào việc kiểm tra hành vi của một phương thức đơn trên một lớp đơn.

Nếu bạn đang thực sự thử nghiệm "nhiều hơn" so với chỉ một phương pháp trên một lớp, ví dụ: làm thế nào một lớp tương tác với các lớp khác, nó có nghĩa là bạn có nhiều khả năng viết một bài kiểm tra "tích hợp", không phải là một thử nghiệm "đơn vị" thực sự.

Lưu ý khác: Tôi không tuyên bố là chuyên gia về thử nghiệm đơn vị!Chúng cực kỳ hữu ích, nhưng tôi vẫn cố gắng thử nghiệm nhiều hơn hầu hết các khía cạnh khác của mã hóa.

Để đọc thêm, tôi khuyên bạn nên "Nghệ thuật thử nghiệm đơn vị" của Roy Osherove. Có những người khác nữa.

The Art of Unit Testing

+0

Ok câu trả lời này giống như câu trả lời lớn về thử nghiệm đơn vị hơn là câu trả lời cho câu hỏi rất cụ thể của bạn, xin lỗi! Hy vọng ai đó thấy nó hữu ích một ngày nào đó :) – GrahamMc

+0

Tôi đồng ý với những gì bạn nói ở đây, nhưng tôi có cảm giác rằng OP thực sự đang viết một bài kiểm tra tích hợp để xác minh xem hệ thống có hoạt động chính xác hay không. Trong vài trường hợp này, bạn thực sự muốn thử nghiệm cơ sở hạ tầng bao gồm cả thùng chứa IoC của bạn và bao gồm cả Membus. Bạn có lẽ nên có một số ít các bài kiểm tra đó, nhưng tuy nhiên những bài kiểm tra đó rất quan trọng. – Steven

+0

@Steven đồng ý! – GrahamMc

4

Như Steven nói trong ý kiến ​​của mình, có vẻ như bạn đang viết một thử nghiệm hội nhập, trong trường hợp này nó làm cho cảm giác sử dụng các container IoC.

Dự án thử nghiệm của bạn phải có Root Root riêng cho cấu hình IoC. Bạn có thể cấu hình container IoC của bạn để trả về một đối tượng giả lập cho AccountCommandHandlers. Kiểm tra của bạn, thay vì kiểm tra các thành viên boolean, thay vào đó có thể kiểm tra xem Handle (CreateCommand) được gọi là ít nhất một lần. Với Moq, nó sẽ giống như thế này:

mock.Verify(foo => foo.Handle(createAccountCommand), Times.AtLeastOnce()); 

Nếu vì bất cứ lý do bạn không thể sử dụng một khuôn khổ giả với cấu hình IoC, nó sẽ dễ dàng để tạo lớp học giả của riêng bạn cho trường hợp này là một thử nghiệm.

4

Một câu hỏi mà bạn cũng nên tự hỏi mình là: Tôi thực sự muốn thử nghiệm điều gì?

Bộ thử nghiệm của bạn không nhất thiết cần phải kiểm tra lib của bên thứ ba. Trong phần trên, membus được thiết kế để gửi các thông điệp đến các trình xử lý, các kiểm tra trong thư viện đó đảm bảo rằng đây là trường hợp.

Nếu bạn thực sự muốn kiểm tra tin nhắn -> IOC đoàn xử lý, trong trường hợp của Membus bạn có thể viết một chiếc xe buýt -> IOC bộ chuyển đổi để thử nghiệm:

public class TestAdapter : IocAdapter 
{ 
    private readonly object[] _handlers; 

    public TestAdapter(params object[] handlers) 
    { 
     _handlers = handlers; 
    } 

    public IEnumerable<object> GetAllInstances(Type desiredType) 
    { 
     return _handlers; 
    } 
} 

Và sau đó sử dụng nó với các trường hợp dưới kiểm tra.

 var bus = 
      BusSetup.StartWith<Conservative>() 
        .Apply<IoCSupport>(
         ioc => ioc.SetAdapter(new TestAdapter(new Handler<XYZ>())) 
        .SetHandlerInterface(typeof (IHandler<>))) 
        .Construct(); 

nơi bạn sẽ giữ phiên bản trình xử lý xung quanh để thực hiện xác nhận chống lại nó.OTOH nếu bạn tin tưởng thư viện để làm công việc của nó, bạn chỉ đơn giản là sẽ mới lên xử lý và kiểm tra logic nội bộ của nó.

+0

điểm tốt, tuy nhiên có một số công cụ khác đi (serialization) trên cho các bài kiểm tra khác (tôi đã không bao gồm như không phức tạp những điều), membus thực sự chỉ được liệt kê không phải là một tạo tác của thử nghiệm thu gọn. membus là tuyệt vời btw :) – g18c

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