用Moqvalidation一个特定的参数

public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully() { var messageServiceClientMock = new Mock<IMessageServiceClient>(); var queueableMessage = CreateSingleQueueableMessage(); var message = queueableMessage[0]; var xml = QueueableMessageAsXml(queueableMessage); messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(xml)).Verifiable(); //messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable(); var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>(); serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(essageServiceClientMock.Object); var loggerStub = new Mock<ILogger>(); var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object); client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message}); //messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(xml), Times.Once()); messageServiceClientMock.Verify(); } 

我开始使用Moq并挣扎了一下。 我试图validationmessageServiceClient接收正确的参数,这是一个XmlElement,但我找不到任何方式使其工作。 只有当我没有检查一个特定的值时,它才有效。

有任何想法吗?

部分答案:我已经find了一种方法来testing发送到代理的XML是正确的,但我仍然不认为这是正确的方式来做到这一点。

 public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully() { var messageServiceClientMock = new Mock<IMessageServiceClient>(); messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable(); var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>(); serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(messageServiceClientMock.Object); var loggerStub = new Mock<ILogger>(); var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object); var message = CreateMessage(); client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message}); messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(It.Is<XmlElement>(xmlElement => XMLDeserializer<QueueableMessage>.Deserialize(xmlElement).Messages.Contains(message))), Times.Once()); } 

顺便说一下,我怎样才能从validation呼叫中提取expression式?

如果validation逻辑不平凡,写一个大的lambda方法会很麻烦(如你的例子所示)。 你可以把所有的testing语句放在一个单独的方法中,但是我不喜欢这样做,因为它会中断阅读testing代码的stream程。

另一个select是在Setup调用中使用callback来存储传递到模拟方法的值,然后编写标准的Assert方法来validation它。 例如:

 // Arrange MyObject saveObject; mock.Setup(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>())) .Callback<int, MyObject>((i, obj) => saveObject = obj) .Returns("xyzzy"); // Act // ... // Assert // Verify Method was called once only mock.Verify(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()), Times.Once()); // Assert about saveObject Assert.That(saveObject.TheProperty, Is.EqualTo(2)); 

我一直在以同样的方式validation电话 – 我相信这是正确的方法。

 mockSomething.Verify(ms => ms.Method( It.IsAny<int>(), It.Is<MyObject>(mo => mo.Id == 5 && mo.description = "test") ), Times.Once()); 

如果你的lambdaexpression式变得笨拙,你可以创build一个函数,将MyObject作为input并输出true / false …

 mockSomething.Verify(ms => ms.Method( It.IsAny<int>(), It.Is<MyObject>(mo => MyObjectFunc(mo)) ), Times.Once()); private bool MyObjectFunc(MyObject myObject) { return myObject.Id == 5 && myObject.description == "test"; } 

另外,请注意Mock中的一个错误,其中错误消息指出该方法在完全不被调用时被多次调用。 他们现在可能已经修好了 – 但是如果你看到这个信息,你可能会考虑validation这个方法实际上是被调用的。

编辑:下面是一个示例调用validation多次的情况下,您要validation您调用列表中的每个对象的函数(例如)。

 foreach (var item in myList) mockRepository.Verify(mr => mr.Update( It.Is<MyObject>(i => i.Id == item.Id && i.LastUpdated == item.LastUpdated), Times.Once()); 

相同的设置方法…

 foreach (var item in myList) { var stuff = ... // some result specific to the item this.mockRepository .Setup(mr => mr.GetStuff(item.itemId)) .Returns(stuff); } 

所以每次GetStuff被调用的itemId,它会返回特定的项目的东西。 或者,你可以使用一个函数,它将itemId作为input并返回一些东西。

 this.mockRepository .Setup(mr => mr.GetStuff(It.IsAny<int>())) .Returns((int id) => SomeFunctionThatReturnsStuff(id)); 

有一段时间,我在博客上看到的另一种方法(Phil Haack也许?)已经设置了从某种出列对象返回的设置 – 每次函数被调用时,都会从队列中拉出一个项目。

更简单的方法是做:

 ObjectA.Verify( a => a.Execute( It.Is<Params>(p => p.Id == 7) ) ); 

我相信Moq会检查平等的问题。 而且,由于XmlElement不会覆盖Equals,因此实现将检查引用是否相等。

你不能使用自定义对象,所以你可以重写equals?