Search code examples
c#unit-testingmoqrhino-mocks

What is Moq's equivalent of LastCall in RhinoMocks?


I'm upgrading to .Net Core which involves converting a number of unit tests from RhinoMocks to Moq since it supports .Net Standard.

I've been converting LastCall by repeating the most recent mocked call, but I'm confused because I have a unit test where LastCall.Throw(Exception); occurs before any mocked calls do.

As I understand LastCall, it allows you to do something additional to the last call that was added, but I know I don't understand something because in my mind LastCall can't come before at least one mocked call.

The unit test looks something like:

MockRepository mock = new MockRepository();
 ...
using (mocks.Record())
{
    nonMockedObject.DoSomething();
    LastCall.Throw(Exception);
    Expect.Call(mockedObject.Stuff()).Return(true).Repeat.Any();
    ...
}

Any help on understanding RhinoMocks's LastCall or how to convert it to Moq would be appreciated.


Solution

  • From the link, https://www.codeproject.com/Articles/11294/Rhino-Mocks-2-2#Capabilities, Below are some important points to be noted.

    We use the Expect.Call() for methods that has return values, and LastCall for methods that return void to get the IMethodOptions interface. I find the Expect.Call() syntax a bit clearer, but there is no practical difference between the two.

    I would recommend using Expect wherever possible (anything that return a value). For properties setters, or methods returning void, the Expect syntax is not applicable, since there is no return value.

    Thus, the need for the LastCall. The idea of Last Call is pervasive in the record state, you can only set the method options for the last call - even Expect.Call() syntax is merely a wrapper around LastCall.

    Conclusion : Do not use LastCall inside record state. As you are migrating from RhinoMocks to Moq, You can Ignore LastCall.

    Coming to the code which you have shared, You can mock functions which returns a value using moq as below,

    Mock<IYourRepository> mockRepository = new Mock<IYourRepository>();
    mockRepository.Setup(m=> m.YourMethodName(It.IsAny<int>())).Returns(new List<string>());
    mockRepository.Setup(m=> m.YourMethodName(It.Is<int>(x=> x == 0)).Throws<ArgumentException>();
    

    For Methods which do not return anything, You can set like below,

    Mock<IYourRepository> mockRepository = new Mock<IYourRepository>();
    mockRepository.Setup(m=> m.YourVoidMethodName(It.IsAny<int>())).Verifiable();;
    mockRepository.Setup(m=> m.YourVoidMethodName(It.IsAny<int>())).Throws<Exception>();
    mockRepository.Setup(m=> m.YourAsyncVoidMethodName(It.IsAny<int>())).Returns(Task.Completed); // public async Task YourAsyncVoidMethodName(){}
    

    To address the comment,

    LastCall.Repeat.AtLeastOnce(); would be converted to Moq as

    Mock<IYourRepository> mockRepository = new Mock<IYourRepository>(); 
    mockRepository.Verify(m=> m.NotVoidMethodName(It.IsAny<int>()), Times.AtLeastOnce());