2012-05-15 37 views
36

Tôi cần phải kiểm tra các phương pháp sau đây:Sử dụng Moq để xác minh các cuộc gọi được thực hiện theo đúng thứ tự

CreateOutput(IWriter writer) 
{ 
    writer.Write(type); 
    writer.Write(id); 
    writer.Write(sender); 

    // many more Write()s... 
} 

Tôi đã tạo một Moq'd IWriter và tôi muốn đảm bảo rằng các Write() phương pháp này được gọi là trong đúng thứ tự.

Tôi đã mã kiểm tra sau:

var mockWriter = new Mock<IWriter>(MockBehavior.Strict); 
var sequence = new MockSequence(); 
mockWriter.InSequence(sequence).Setup(x => x.Write(expectedType)); 
mockWriter.InSequence(sequence).Setup(x => x.Write(expectedId)); 
mockWriter.InSequence(sequence).Setup(x => x.Write(expectedSender)); 

Tuy nhiên, cuộc gọi thứ hai để Write() trong CreateOutput() (để viết giá trị id) ném một MockException với thông điệp "IWriter.Write() gọi thất bại với Tất cả lời gọi trên mô hình phải có thiết lập tương ứng. ".

Tôi cũng thấy khó tìm thấy bất kỳ tài liệu/ví dụ cập nhật nhất định nào về các chuỗi Moq.

Tôi có làm điều gì sai hay không thể thiết lập chuỗi bằng cách sử dụng cùng một phương pháp? Nếu không, có cách nào khác mà tôi có thể sử dụng hay không (tốt nhất là sử dụng Moq/NUnit)?

+0

thể trùng lặp của [Làm thế nào để kiểm tra trật tự gọi phương pháp với Moq] (http://stackoverflow.com/questions/1765738/how- to-test-method-call-order-with-moq) – sloth

+0

[Bản phát hành mới nhất của Moq, v4.2] (https://github.com/Moq/moq) đã "cải thiện thử nghiệm chuỗi yêu cầu giả" theo [ghi chú phát hành] (https://github.com/Moq/moq4/blob/master/ReleaseNotes.md). –

+1

Tôi đang sử dụng v.4.2.x và có thể xác nhận rằng chức năng trình tự đang hoạt động đối với tôi. –

Trả lời

38

Có lỗi khi using MockSequence on same mock. Nó chắc chắn sẽ được cố định trong phiên bản sau của thư viện Moq (bạn cũng có thể sửa chữa nó bằng tay bằng cách thay đổi thực hiện Moq.MethodCall.Matches).

Nếu bạn muốn sử dụng Moq chỉ, sau đó bạn có thể xác minh để gọi phương thức qua callbacks:

int callOrder = 0; 
writerMock.Setup(x => x.Write(expectedType)).Callback(() => Assert.That(callOrder++, Is.EqualTo(0))); 
writerMock.Setup(x => x.Write(expectedId)).Callback(() => Assert.That(callOrder++, Is.EqualTo(1))); 
writerMock.Setup(x => x.Write(expectedSender)).Callback(() => Assert.That(callOrder++, Is.EqualTo(2))); 
+1

Cảm ơn thông tin, tôi đã sử dụng phương pháp này. Hy vọng sẽ có bản phát hành sau của Moq! Một trong những công cụ kiểm tra tốt nhất là ... –

+1

Một từ cảnh báo ở đây, nếu phương thức 'Write()' không bao giờ được gọi, thì không có callback nào có cơ hội khẳng định bất cứ điều gì. Hãy chắc chắn để thêm một bắt tất cả xác minh rằng phương thức được gọi ít nhất một lần. –

+0

Có cuộc thảo luận đang diễn ra về github về sắp xếp thứ tự, cho bất kỳ ai muốn đóng góp/nhận xét: https://github.com/moq/moq4/issues/75 – Ray

0

Tôi cho rằng expectedId không phải là những gì bạn mong đợi.

Tuy nhiên tôi có lẽ chỉ cần viết triển khai IWriter của riêng mình để xác minh trong trường hợp này ... có thể dễ dàng hơn nhiều (và dễ thay đổi sau này).

Xin lỗi vì không có lời khuyên nào về Moq trực tiếp. Tôi thích nó, nhưng chưa làm điều này.

bạn có cần phải thêm .Verify() ở cuối mỗi thiết lập không? (Đó thực sự là một đoán mặc dù tôi sợ).

+0

Tôi đã kiểm tra kỹ và các giá trị là chính xác và như mong đợi. Lăn mocks của riêng tôi là một cái gì đó tôi cố gắng tránh bây giờ tôi sử dụng Moq, nhưng có thể phải nghỉ mát! Và Verify() không thể được thêm sau khi thiết lập, chỉ Verifiable() - mà thật đáng buồn làm cho không có sự khác biệt. Cảm ơn cho các con trỏ mặc dù. –

8

tôi đã quản lý để có được những hành vi của tôi muốn, nhưng nó đòi hỏi tải một thư viện của bên thứ 3 từ http://dpwhelan.com/blog/software-development/moq-sequences/

Trình tự sau đó có thể được kiểm tra bằng cách sử dụng sau đây:

var mockWriter = new Mock<IWriter>(MockBehavior.Strict); 
using (Sequence.Create()) 
{ 
    mockWriter.Setup(x => x.Write(expectedType)).InSequence(); 
    mockWriter.Setup(x => x.Write(expectedId)).InSequence(); 
    mockWriter.Setup(x => x.Write(expectedSender)).InSequence(); 
} 

Tôi đã thêm này như là một câu trả lời một phần để giúp tài liệu giải pháp này, nhưng tôi vẫn quan tâm đến việc một cái gì đó tương tự có thể đạt được bằng cách sử dụng Moq 4,0 một mình.

Tôi không chắc liệu Moq có còn đang phát triển hay không, nhưng khắc phục sự cố với MockSequence hoặc bao gồm phần mở rộng moq-sequences trong Moq sẽ rất hữu ích.

+0

xấu hổ bạn không thể chiều. Cool không biết rằng tồn tại: D. Nhưng bạn đang thực sự bướng bỉnh btw một khi bạn nhận được vào lãnh thổ này mà có lẽ lý do tại sao moq là một chút thiếu trong lĩnh vực này - và yeah dự án có vẻ rất yên tĩnh. Nhìn vào các vấn đề của nó và trình tự đã được trên đó trong 4 năm xuất sắc. Tôi cũng nhận thấy bản phát hành mới nhất không có tên cuối cùng. –

3

Gần đây, tôi đặt cùng hai tính năng cho Moq: VerifyInSequence() và VerifyNotInSequence(). Họ làm việc ngay cả với Loose Mocks.Tuy nhiên, đây là những chỉ có sẵn trong một ngã ba kho moq:

https://github.com/grzesiek-galezowski/moq4

và chờ đợi nhiều ý kiến ​​và thử nghiệm trước khi quyết định liệu họ có thể được bao gồm trong releaase moq chính thức. Tuy nhiên, không có gì ngăn cản bạn tải xuống nguồn dưới dạng ZIP, xây dựng nó thành một dll và thử nó. Sử dụng các tính năng này, việc xác minh chuỗi bạn cần có thể được viết như vậy:

 
var mockWriter = new Mock<IWriter>() { CallSequence = new LooseSequence() }; 

//perform the necessary calls 

mockWriter.VerifyInSequence(x => x.Write(expectedType)); 
mockWriter.VerifyInSequence(x => x.Write(expectedId)); 
mockWriter.VerifyInSequence(x => x.Write(expectedSender)); 

(lưu ý rằng bạn có thể sử dụng hai chuỗi khác, tùy thuộc vào nhu cầu của bạn chuỗi Loose sẽ cho phép bất kỳ cuộc gọi giữa những người bạn muốn xác minh. StrictSequence sẽ không cho phép điều này và StrictAnytimeSequence giống như StrictSequence (không có cuộc gọi phương thức giữa các cuộc gọi đã xác minh), nhưng cho phép trình tự được gọi trước bởi bất kỳ số lượng cuộc gọi tùy ý nào.

Nếu bạn quyết định thử tính năng thử nghiệm này, vui lòng nhận xét với suy nghĩ của bạn về: https://github.com/Moq/moq4/issues/21

Cảm ơn!

7

Tôi đã viết một phương pháp mở rộng sẽ xác nhận dựa trên thứ tự gọi.

public static class MockExtensions 
{ 
    public static void ExpectsInOrder<T>(this Mock<T> mock, params Expression<Action<T>>[] expressions) where T : class 
    { 
    // All closures have the same instance of sharedCallCount 
    var sharedCallCount = 0; 
    for (var i = 0; i < expressions.Length; i++) 
    { 
     // Each closure has it's own instance of expectedCallCount 
     var expectedCallCount = i; 
     mock.Setup(expressions[i]).Callback(
     () => 
      { 
      Assert.AreEqual(expectedCallCount, sharedCallCount); 
      sharedCallCount++; 
      }); 
    } 
    } 
} 

Nó hoạt động bằng cách tận dụng cách đóng mà làm việc liên quan đến biến phức tạp. Vì chỉ có một khai báo cho sharedCallCount, tất cả các bao đóng sẽ có tham chiếu đến cùng một biến. Với expectedCallCount, một cá thể mới được khởi tạo mỗi lần lặp của vòng lặp (trái với việc đơn giản sử dụng i trong phần đóng). Bằng cách này, mỗi đóng cửa có một bản sao của tôi chỉ phạm vi chính nó để so sánh với sharedCallCount khi các biểu thức được gọi.

Đây là kiểm tra đơn vị nhỏ cho tiện ích. Lưu ý rằng phương thức này được gọi trong phần thiết lập của bạn, không phải là phần xác nhận của bạn.

[TestFixture] 
public class MockExtensionsTest 
{ 
    [TestCase] 
    { 
    // Setup 
    var mock = new Mock<IAmAnInterface>(); 
    mock.ExpectsInOrder(
     x => x.MyMethod("1"), 
     x => x.MyMethod("2")); 

    // Fake the object being called in order 
    mock.Object.MyMethod("1"); 
    mock.Object.MyMethod("2"); 
    } 

    [TestCase] 
    { 
    // Setup 
    var mock = new Mock<IAmAnInterface>(); 
    mock.ExpectsInOrder(
     x => x.MyMethod("1"), 
     x => x.MyMethod("2")); 

    // Fake the object being called out of order 
    Assert.Throws<AssertionException>(() => mock.Object.MyMethod("2")); 
    } 
} 

public interface IAmAnInterface 
{ 
    void MyMethod(string param); 
} 
2

Giải pháp đơn giản nhất sẽ được sử dụng một Queue:

var expectedParameters = new Queue<string>(new[]{expectedType,expectedId,expectedSender}); 
mockWriter.Setup(x => x.Write(expectedType)) 
      .Callback((string s) => Assert.AreEqual(expectedParameters.Dequeue(), s)); 
Các vấn đề liên quan