Verifying a specific parameter with Moq

后端 未结 5 2010
生来不讨喜
生来不讨喜 2020-12-22 19:38
public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully()
{
    var messageServiceClientMock = new Mock();
    var queueableMess         


        
相关标签:
5条回答
  • 2020-12-22 20:05

    If the verification logic is non-trivial, it will be messy to write a large lambda method (as your example shows). You could put all the test statements in a separate method, but I don't like to do this because it disrupts the flow of reading the test code.

    Another option is to use a callback on the Setup call to store the value that was passed into the mocked method, and then write standard Assert methods to validate it. For example:

    // 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));
    
    0 讨论(0)
  • 2020-12-22 20:09

    A simpler way would be to do:

    ObjectA.Verify(
        a => a.Execute(
            It.Is<Params>(p => p.Id == 7)
        )
    );
    
    0 讨论(0)
  • 2020-12-22 20:14

    I've been verifying calls in the same manner - I believe it is the right way to do it.

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

    If your lambda expression becomes unwieldy, you could create a function that takes MyObject as input and outputs 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";
    }
    

    Also, be aware of a bug with Mock where the error message states that the method was called multiple times when it wasn't called at all. They might have fixed it by now - but if you see that message you might consider verifying that the method was actually called.

    EDIT: Here is an example of calling verify multiple times for those scenarios where you want to verify that you call a function for each object in a list (for example).

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

    Same approach for setup...

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

    So each time GetStuff is called for that itemId, it will return stuff specific to that item. Alternatively, you could use a function that takes itemId as input and returns stuff.

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

    One other method I saw on a blog some time back (Phil Haack perhaps?) had setup returning from some kind of dequeue object - each time the function was called it would pull an item from a queue.

    0 讨论(0)
  • 2020-12-22 20:15

    I believe that the problem in the fact that Moq will check for equality. And, since XmlElement does not override Equals, it's implementation will check for reference equality.

    Can't you use a custom object, so you can override equals?

    0 讨论(0)
  • 2020-12-22 20:16

    Had one of these as well, but the parameter of the action was an interface with no public properties. Ended up using It.Is() with a seperate method and within this method had to do some mocking of the interface

    public interface IQuery
    {
        IQuery SetSomeFields(string info);
    }
    
    void DoSomeQuerying(Action<IQuery> queryThing);
    
    mockedObject.Setup(m => m.DoSomeQuerying(It.Is<Action<IQuery>>(q => MyCheckingMethod(q)));
    
    private bool MyCheckingMethod(Action<IQuery> queryAction)
    {
        var mockQuery = new Mock<IQuery>();
        mockQuery.Setup(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition())
        queryAction.Invoke(mockQuery.Object);
        mockQuery.Verify(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition(), Times.Once)
        return true
    }
    
    0 讨论(0)
提交回复
热议问题