2010-02-19 34 views
102

Tôi có một giao diện từ trước ...Mocking Phương pháp mở rộng với Moq

public interface ISomeInterface 
{ 
    void SomeMethod(); 
} 

và tôi đã mở rộng intreface này sử dụng một mixin ...

public static class SomeInterfaceExtensions 
{ 
    public static void AnotherMethod(this ISomeInterface someInterface) 
    { 
     // Implementation here 
    } 
} 

Tôi có một thats lớp gọi này mà tôi muốn thử nghiệm ...

public class Caller 
{ 
    private readonly ISomeInterface someInterface; 

    public Caller(ISomeInterface someInterface) 
    { 
     this.someInterface = someInterface; 
    } 

    public void Main() 
    { 
     someInterface.AnotherMethod(); 
    } 
} 

và thử nghiệm nơi tôi muốn giả lập giao diện và xác minh cuộc gọi đến phương pháp mở rộng ...

[Test] 
    public void Main_BasicCall_CallsAnotherMethod() 
    { 
     // Arrange 
     var someInterfaceMock = new Mock<ISomeInterface>(); 
     someInterfaceMock.Setup(x => x.AnotherMethod()).Verifiable(); 

     var caller = new Caller(someInterfaceMock.Object); 

     // Act 
     caller.Main(); 

     // Assert 
     someInterfaceMock.Verify(); 
    } 

Chạy tuy nhiên thử nghiệm này tạo ra một ngoại lệ ...

System.ArgumentException: Invalid setup on a non-member method: 
x => x.AnotherMethod() 

Câu hỏi của tôi là, là có một cách tốt đẹp để thử ra các cuộc gọi mixin?

+2

Theo kinh nghiệm của tôi, các thuật ngữ mixin và các phương pháp mở rộng là những điều riêng biệt.Tôi muốn sử dụng sau này trong trường hợp này để tránh hỗn hợp: P –

+2

Bản sao của: http://stackoverflow.com/questions/562129/how-do-i-use-moq-to-mock-an-extension-method. – Oliver

Trả lời

18

Bạn không thể "trực tiếp" giả lập phương thức tĩnh (do đó là phương pháp mở rộng) với khung mocking. Bạn có thể thử Moles (http://research.microsoft.com/en-us/projects/pex/downloads.aspx), một công cụ miễn phí của Microsoft thực hiện một cách tiếp cận khác. Đây là mô tả về công cụ:

Vai trò là một khung trọng lượng nhẹ cho các phần tử thử nghiệm và đường vòng trong .NET dựa trên các đại biểu.

Các nốt ruồi có thể được sử dụng để hủy bỏ bất kỳ phương thức .NET nào, bao gồm các phương pháp không ảo/tĩnh trong các loại kín.

Bạn có thể sử dụng Moles với bất kỳ khung kiểm tra nào (nó độc lập về điều đó).

+2

Bên cạnh Moles, còn có các khuôn khổ mocking khác (không miễn phí) sử dụng API profiler của .NET để giả lập các đối tượng và do đó có thể thay thế bất kỳ cuộc gọi nào. Hai tôi biết là [JustMock của Telerik] (http://www.telerik.com/products/mocking.aspx) và [TypeMock Isolator] (http://www.typemock.com/typemock-isolator-product3). –

+3

Các nốt ruồi về lý thuyết là tốt, nhưng tôi đã tìm thấy ba vấn đề khi tôi thử nghiệm nó đã ngăn tôi sử dụng nó ... 1) Nó không chạy trong Resharper NUnit runner 2) Bạn cần phải tự tạo ra một lắp ráp nốt ruồi cho mỗi lắp ráp stubbed 3) Bạn cần phải tự tạo lại một hội đồng nốt ruồi bất cứ khi nào một phương pháp stubbed thay đổi. –

10

Tôi đã sử dụng Trình bao bọc để giải quyết vấn đề này. Tạo một đối tượng bao bọc và truyền phương thức giả của bạn.

Xem Mocking Static Methods for Unit Testing bởi Paul Irwin, nó có các ví dụ hay.

+0

Tôi thích câu trả lời này bởi vì những gì nó đang nói (không trực tiếp nói nó) là bạn cần phải thay đổi mã của bạn để làm cho nó có thể kiểm chứng. Đó chỉ là cách nó hoạt động. Hiểu rằng trong thiết kế microchip/IC/ASIC, những chip này không chỉ được thiết kế để hoạt động mà còn được thiết kế hơn nữa để có thể kiểm tra được, bởi vì nếu bạn không thể thử nghiệm vi mạch, điều đó vô ích - bạn không thể đảm bảo nó sẽ công việc. Cũng vậy với phần mềm. Nếu bạn chưa xây dựng nó để có thể kiểm chứng, nó ... vô dụng. Xây dựng nó để có thể kiểm tra, mà trong một số trường hợp có nghĩa là viết lại mã (và sử dụng trình bao bọc), và sau đó xây dựng các bài kiểm tra tự động kiểm tra nó. –

1

Tôi thích sử dụng trình bao bọc (mẫu bộ điều hợp) khi tôi gói chính đối tượng đó. Tôi không chắc chắn tôi sẽ sử dụng nó để gói một phương thức mở rộng, mà không phải là một phần của đối tượng.

Tôi sử dụng nội dung Lazy Injectable nội bộ của một trong hai loại Hành động, Func, Predicate hoặc ủy quyền và cho phép tiêm (hoán đổi) phương pháp trong khi kiểm tra đơn vị.

internal Func<IMyObject, string, object> DoWorkMethod 
    { 
     [ExcludeFromCodeCoverage] 
     get { return _DoWorkMethod ?? (_DoWorkMethod = (obj, val) => { return obj.DoWork(val); }); } 
     set { _DoWorkMethod = value; } 
    } private Func<IMyObject, string, object> _DoWorkMethod; 

Sau đó, bạn gọi hàm Func thay cho phương thức thực tế.

public object SomeFunction() 
    { 
     var val = "doesn't matter for this example"; 
     return DoWorkMethod.Invoke(MyObjectProperty, val); 
    } 

Đối với một ví dụ hoàn chỉnh hơn, hãy kiểm tra http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/

+0

Điều này là tốt, nhưng độc giả nên lưu ý rằng _DoWorkMethod là một trường mới của lớp mà mỗi cá thể của lớp bây giờ phải phân bổ thêm một trường nữa. Thật hiếm khi điều này quan trọng, nhưng đôi khi nó phụ thuộc vào số lượng cá thể bạn đang phân bổ cùng một lúc. Bạn có thể giải quyết vấn đề này bằng cách tạo _DoWorkMethod tĩnh. Nhược điểm của điều đó là nếu bạn có các bài kiểm tra đơn vị chạy đồng thời, hai bài kiểm tra đơn vị khác nhau có thể sửa đổi cùng một giá trị tĩnh sẽ hoàn thành. – zumalifeguard

3

tôi thấy rằng tôi phải khám phá bên trong của phương pháp khuyến nông Tôi đã cố gắng để thử đầu vào cho, và nhạo báng những gì đang xảy ra bên trong sự mở rộng.

Tôi đã xem là tiện ích mở rộng tĩnh, giống như đặt mã trực tiếp vào phương pháp của bạn, vì vậy bạn cần giả lập điều gì xảy ra bên trong tiện ích chứ không phải chính tiện ích.

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