Chế nhạo đối tượng với Moq khi hàm tạo có tham số


92

Tôi có một đối tượng mà tôi đang cố gắng chế nhạo bằng cách sử dụng moq. Hàm tạo của đối tượng có các tham số bắt buộc:

public class CustomerSyncEngine {
    public CustomerSyncEngine(ILoggingProvider loggingProvider, 
                              ICrmProvider crmProvider, 
                              ICacheProvider cacheProvider) { ... }
}

Bây giờ tôi đang cố gắng tạo mô hình cho đối tượng này bằng cách sử dụng cú pháp v3 "setup" hoặc v4 "Mock.Of" của moq nhưng không thể tìm ra điều này ... mọi thứ tôi đang thử đều không xác thực. Đây là những gì tôi có cho đến nay, nhưng dòng cuối cùng là cung cấp cho tôi một đối tượng thực sự, không phải mô phỏng. Lý do tôi làm điều này là vì tôi có các phương thức trên CustomerSyncEngine mà tôi muốn xác minh đang được gọi ...

// setup
var mockCrm = Mock.Of<ICrmProvider>(x => x.GetPickLists() == crmPickLists);
var mockCache = Mock.Of<ICacheProvider>(x => x.GetPickLists() == cachePickLists);
var mockLogger = Mock.Of<ILoggingProvider>();

// need to mock the following, not create a real class like this...
var syncEngine = new CustomerSyncEngine(mockLogger, mockCrm, mockCache);

Bạn có thể cung cấp một phương pháp mẫu mà bạn muốn xác minh việc được gọi không?
Ciaran

4
Vì vậy, nếu tôi có phụ thuộc vào Lớp chứ không phải Giao diện, tôi phải bắt chước ngay cả những phụ thuộc của chúng, điều này sẽ đi xuống một cách đệ quy. Cuối cùng, tôi buộc phải sử dụng một số giao diện để giữ cho mã của mình có thể kiểm tra được, ngay cả khi tôi không cần các giao diện trong mã của mình. Tôi nghĩ rằng quá nhiều giao diện là một mùi lớn hơn so với việc chế nhạo các lớp bê tông ...
Tarion

Câu trả lời:


34

Dòng cuối cùng cung cấp cho bạn một ví dụ thực tế vì bạn đang sử dụng từ khóa mới, không chế giễu CustomerSyncEngine.

Bạn nên sử dụng Mock.Of<CustomerSyncEngine>()

Vấn đề duy nhất với các kiểu Mocking Concrete là Moq sẽ cần một phương thức khởi tạo mặc định công khai (không có tham số) HOẶC bạn cần tạo Moq với đặc tả constructor arg. http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html

Điều tốt nhất cần làm là nhấp chuột phải vào lớp của bạn và chọn giao diện Trích xuất.


3
Liên quan đến vấn đề này, một giải pháp thay thế là sử dụng một thùng chứa AutoMocking. Yêu thích của tôi là Machine.Fakes kết hợp với Machine.Specification, sử dụng thùng chứa tự động giúp dễ dàng kiểm tra các diện tích bề mặt nhỏ hơn. Giả sử Andrew cần kiểm tra một phương pháp CustomerSyncEnginechỉ sử dụng ICrmProvidervới các triển khai chế tạo truyền thống phải được cung cấp cho cả 3 giao diện trong khi một vùng chứa tự động cho phép bạn chỉ cung cấp một giao diện.
Chris Marisic

73

Thay đổi dòng cuối cùng thành

var syncEngine = new Mock<CustomerSyncEngine>(mockLogger, mockCrm, mockCache).Object;

và nó sẽ hoạt động


3
Không chắc chắn làm thế nào nhận xét này áp dụng cho câu trả lời của tôi?
Suhas

2
Bởi vì điều này sẽ gây ra lỗi biên dịch dưới dạng mockLogger và những người khác sẽ ném một ngoại lệ rằng họ không có thuộc tính Đối tượng
Justin Pihony

2
Vì OP đang sử dụng Mock.Of <T> () để tạo mocks của các loại logger, crm và cache, đối tượng được trả về được trả về dưới dạng T, không phải là Mock <T>. Vì vậy, mockLogger.Object, v.v. không cần thiết khi cung cấp chúng cho Mock of CustomerSyncEngine và như @JustinPihony đã đề cập, sẽ hiển thị cho bạn lỗi thời gian thiết kế.
Josh Gust

1
@suhas Không nên là của anh ấynew Mock<CustomerSyncEngine>(new object[]{mockLogger, mockCrm, mockCache}).Object;
GiriB

@GiriB không cần thiết, nhưng có thể, vì mô hình được định nghĩa bằng Params. public Mock (params object [] args)
Jiří Herník
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.