Làm thế nào để tôi Moq một phương thức có đối số tùy chọn trong chữ ký của nó mà không chỉ định rõ ràng nó hoặc sử dụng quá tải?


119

Cho giao diện sau:

public interface IFoo
{
    bool Foo(string a, bool b = false);
}

Cố gắng chế nhạo nó bằng Moq:

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);

đưa ra lỗi sau tại thời điểm biên dịch:

Cây biểu thức không được chứa lệnh gọi hoặc lệnh gọi sử dụng các đối số tùy chọn

Tôi đã tìm thấy vấn đề ở trên được nêu ra như một cải tiến trong danh sách các vấn đề của Moq và nó dường như được gán cho bản phát hành 4.5 (bất cứ khi nào có).

Câu hỏi của tôi là: tôi nên làm gì khi những điều trên sẽ không sớm được khắc phục? Có phải các tùy chọn của tôi chỉ để đặt rõ ràng giá trị mặc định của tham số tùy chọn mỗi khi tôi mô phỏng nó (loại nào đánh bại quan điểm chỉ định một tham số ngay từ đầu) hoặc để tạo quá tải mà không có bool (như những gì tôi đã làm trước C # 4)?

Hoặc có ai đã tìm ra một cách thông minh hơn để khắc phục vấn đề này?


5
Có hợp lý không khi chỉ định It.IsAny <bool> () cho tham số thứ hai?
Paul d'Aoust

Một năm rưỡi sau, điều này vẫn đúng ..
Mukus

@Mukus, thoải mái bỏ PR đi anh bạn.
IamDOM

Câu trả lời:


91

Tôi tin rằng lựa chọn duy nhất của bạn lúc này là đưa boolthông số vào thiết lập cho Foo.

Tôi không nghĩ rằng nó đánh bại mục đích chỉ định một giá trị mặc định. Giá trị mặc định là một sự thuận tiện cho việc gọi mã, nhưng tôi nghĩ rằng bạn nên rõ ràng trong các thử nghiệm của mình. Giả sử bạn có thể bỏ qua việc chỉ định booltham số. Điều gì xảy ra nếu trong tương lai, ai đó thay đổi giá trị mặc định của bthành true? Điều này sẽ dẫn đến các xét nghiệm thất bại (và đúng là như vậy), nhưng họ sẽ khó khăn hơn để sửa chữa vì sự giả định ẩn đó bfalse. Chỉ định rõ ràng booltham số có một lợi ích khác: nó cải thiện khả năng đọc các bài kiểm tra của bạn. Ai đó lướt qua chúng sẽ nhanh chóng biết rằng có một Foohàm chấp nhận hai tham số. Đó là 2 xu của tôi, ít nhất :)

Đối với việc chỉ định nó mỗi khi bạn mô phỏng nó, đừng trùng lặp mã: tạo và / hoặc khởi tạo mô hình trong một hàm, để bạn chỉ có một điểm thay đổi duy nhất. Nếu bạn thực sự muốn, bạn có thể khắc phục sự thiếu hụt rõ ràng của Moq ở đây bằng cách sao chép Foocác tham số của vào hàm khởi tạo này:

public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false)
{
    if(!b)
    {
        fooMock.Setup(mock => mock.Foo(a, b)).Returns(false);
    }
    else
    {
        ...
    }
}

1
Câu trả lời xuất sắc; Tôi đã tiếp tục và chỉ rõ nó một cách rõ ràng trong phần chế nhạo của mình nhưng câu trả lời của bạn xác nhận một cách rất rõ ràng và hợp lý tại sao tôi nên làm theo cách này. Cảm ơn, @Chris.
Appulus

9
thay đổi tham số mặc định "nên" phá vỡ các thử nghiệm. Không có thử nghiệm không thành công khi thay đổi mặc định có thể là một dấu hiệu của thử nghiệm kém. Mã có thể sử dụng các giá trị mặc định nhưng các bài kiểm tra thì không?
Pop Catalin

Đã được một thời gian, nhưng tôi đã thử cách tiếp cận này với Moq khi cố gắng mô phỏng một giao diện (IDConnection trong Dapper) và tôi vẫn gặp lỗi tương tự. Bất kỳ ý tưởng tại sao? Dòng mẫu: mockDB.Setup (x => x.Query <MyObject> (It.IsAny <string> (), It.IsAny <DynamicParameters> (), It.IsAny <IDbTransaction> (), false, 600)). Trả về (Danh sách mới <MyObject> ()); Hai giá trị cuối cùng là các tham số tùy chọn trên phương thức tôi đang thiết lập.
Raelshark

4
Arrgggh! if (!x) {} else {}Mô hình chống khủng khiếp :)
nicodemus13

1
@ nicodemus13 Có, nhưng tôi đã cố gắng giữ cho ví dụ mã gần với ví dụ của OP trong câu hỏi nhất có thể. Tôi sẽ không nhất thiết phải ủng hộ nó :)
Chris Mantle

8

Mới gặp sự cố này hôm nay, Moq không hỗ trợ trường hợp sử dụng này. Vì vậy, có vẻ như ghi đè phương thức sẽ là đủ cho trường hợp này.

public interface IFoo
{
    bool Foo(string a);

    bool Foo(string a, bool b);
}

Bây giờ cả hai phương pháp đều có sẵn và ví dụ này sẽ hoạt động:

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);

2

Sử dụng Moq phiên bản 4.10.1, tôi có thể thực hiện những việc sau

Với giao diện:

public interface IFoo
{
    bool Foo(string a, bool b = false);
}

Và Mock

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>(), It.IsAny<bool>())).Returns(false);

Giải quyết cuộc gọi đến Foo với tham số đầu tiên ổn

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.