1

I am using Moq as a mocking framework. I have a situation where I want to execute two different methods, that both call methods an an interface. I want to make sure, that both methods call exactly the same methods on my interface, in the same order and with the same parameters. To illustrate, here is the code:

[TestMethod]
public void UnitTest()
{
var classToTest = new ClassToTest();
Mock<IMyInterface> mock1 = new Mock<IMyInterface>();
// Setup the mock
Mock<IMyInterface> mock2 = new Mock<IMyInterface>();
// Setup the mock


classToTest.MethodToTest(mock1.Object);
classToTest.DifferentMethodToTest(mock2.Object);

// here I need help:
mock1.Verify(theSameMethodsAsMock2);
}

For example, if IMyInterface had two methods, Method1(int i) and Method2(string s), the test should pass if MethodToTest has the structure

void MethodToTest(IMyInterface x)
{
x.Method1(42);
x.Method2("example");
x.Method1(0);
}

and DifferentMethodToTest looks like that:

void MethodToTest(IMyInterface x)
{
int a = 10 + 32;
x.Method1(a);
string s = "examples";
x.Method2(s.Substring(0, 7));
x.Method1(0);
// might also have some code here that not related to IMyInterface at all, 
// e.g. calling methods in other classes and so on
}

Same order, same methods, same parameters. Is this possible with Moq? Or do I need another mocking framework?

SomeBody
  • 7,515
  • 2
  • 17
  • 33
  • you need to be returning some kind of result from the method not void, that way you can check if both perform the same. – level_zebra Feb 19 '20 at 12:01
  • 2
    Is this related? You could use callbacks to keep track of the method calls. https://stackoverflow.com/questions/24027301/how-to-verify-order-of-execution-in-xunit-moq – kor_ Feb 19 '20 at 12:13
  • Sure you can use verify and callbacks, but the core of the problem is that you want to verify that two methods do the same thing. Why don't you move that logic into one method then? – CodeCaster Feb 19 '20 at 12:15
  • @CodeCaster: I refactored a huge method. I want to be sure that I did not introduce any bugs by the refactoring. – SomeBody Feb 19 '20 at 12:18
  • I think you're attempting to solve something that UnitTests are not designed for. Unit testing *Tests a unit of an application without its external dependencies*. You need to ensure your individual methods such as `Method1` and `Method2` are doing what they are ought to. You need to write test cases for these methods. that way you can ensure that you did not introduce any bugs out of refactoring them . You can check this answer here : https://stackoverflow.com/a/60029608/4686729 – Clint Feb 19 '20 at 12:32
  • 1
    Maybe to look into `Capture.In` and then check the order... – Johnny Feb 19 '20 at 12:41

1 Answers1

0

I found a solution by myself which uses InvocationAction:

[TestMethod]
public void Test()
{
var classToTest = new ClassToTest();

var methodCalls1 = new List<string>();
var invocationAction1 = new InvocationAction((ia) =>
{
     string methodCall = $"{ia.Method.Name} was called with parameters {string.Join(", ", ia.Arguments.Select(x => x?.ToString() ?? "null"))}";
     methodCalls1.Add(methodCall);
});
Mock<IMyInterface> mock1 = new Mock<IMyInterface>();
mock1.Setup(x => x.Method1(It.IsAny<int>())).Callback(invocationAction1);
mock1.Setup(x => x.Method2(It.IsAny<string>())).Callback(invocationAction1);

// Same for mock2 ...


classToTest.MethodToTest(mock1.Object);
classToTest.DifferentMethodToTest(mock2.Object);

CollectionAssert.AreEqual(methodCalls1, methodCalls2);
}

I know that the code is very clumsy, especially the string comparisons, but it's sufficient for the time being.

SomeBody
  • 7,515
  • 2
  • 17
  • 33