Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using moq to verify a call to a function with param parameters

Tags:

function

c#

moq

I have an ILogger interface with LogTrace(string value, params object[] parameters). Now I want to verify that the LogTrace is called and the string to log contains some id. The problem is that it can be called differently. E.g. 1) LogTrace("MyString " + id) 2) LogTrace("MyString {0}", id) and so on.

Is there a good way with Moq to verify all the scenarios? I can only think of creating a hand-made mock that will format the string that will be available for verification.

like image 502
Ilya Chernomordik Avatar asked Feb 12 '14 13:02

Ilya Chernomordik


People also ask

How can we use a Moq to check if a method is called with the correct parameters?

When you need to verify that the code under test called a method with the expected parameters, you can mock the method with Moq and use Verify() + It.Is<T>() to check the parameters passed in. Verify() asserts that the method call happened as expected with the specified parameters.

What is verify in mock in C#?

mock. Verify(p => p. Send(It. IsAny<string>())); The Verify method offers additional overloads to specify the fail message and the amount of times the invocation was expected to be performed.

What can be mocked with Moq?

You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces.

What is callback in Moq?

Callbacks. A powerful capability of Moq is to attach custom code to configured methods and properties' getters and setters. This capability is often referred to as Callbacks.


2 Answers

mock.Verify( m => m.LogTrace( It.IsAny<string>(), It.IsAny<object[]>() ) );

The params object[] is passed to the method as object[] anyway so you just have to match the array somehow (as above for example, this accepts anything).

If you need more control over the list, use the It.Is matcher which allows you to create your own predicate:

 mock.Verify( m => m.LogTrace( It.IsAny<string>(),
            It.Is<object[]>(ps =>
                ps != null &&
                ps.Length == 1 &&
                ps[0] is int &&
                (int)ps[0] == 5
            ) ) );

This example shows how to verify if the param list is not empty and contains 5 as the only parameter of type int.

like image 156
Wiktor Zychla Avatar answered Oct 04 '22 22:10

Wiktor Zychla


I don't think there is an easy way for doing what you need here. The problem is that you need to ensure that a certain combination of values will be passed to your method, which results in many different verifiable scenarios:

  • String contains ID AND parameters contains ID - pass
  • String contains ID AND parameters does not contain ID - pass
  • String does not contain ID AND parameters contains ID = pass
  • String does not contain ID AND parameters does not contain ID - fail

However, Moq does not support this sort of conditional expressions between different arguments of your verifiable method. One possible solution is to check for the absence of an id, instead of its presence in either argument. Try something like:

mock.Verify(m => m.LogTrace(
    It.Is<string>(s => !s.Contains(id)), 
    It.Is<object[]>(o => !o.Contains(id))), Times.Never());

What we are doing here is verifying whether the fail condition is ever met - that is, your string does not contain an id, and neither does your object array. We use Times.Never() to make sure that this situation should never happen.

Keep in mind, however, that the code might not be obvious at first glance; make sure you properly explain your intent once you write it.

like image 29
rla4 Avatar answered Oct 04 '22 21:10

rla4