chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
Is there a way using Natural Mocks or AAA to ensure that a method is called at least once with a specific set of parameters if that method can be called more than once in the method being tested?

For example:

public class Foo
  public ILogger Logger { get; set; }

  public void SomeMethod() {
    // I want this one to be ignored
    Logger.Log("Foo");

    // I want to do a substring validation on the message being logged
    Logger.Log("Some message with a really long string");

    // I want this one to be ignored
    Logger.Log("Bar");
}


Essentially, I am only interested in the middle log statement because I want to check that the log entry has a particular substring in it. I don't want the test to be fragile, so I don't want to have to add explicit calls for the Foo and Bar log entries because if additional logging calls are made later on I don't want to have to change my unit test just to account for those...

Something like (pseudo code):

Isolate.Verify.WasCalled((string s) => logger.Log(s))
  .AndArgumentsMatch(s => s.Contains("message with"));


How can you achieve this with the 5.3.4 APIs (Just noticed that 5.3.5 has this but I can't upgrade)?

Thanks in advance,

Carlos
asked by (2.8k points)

3 Answers

0 votes
Hi Carlos,

If you are interested in verifying the call has been made at least once with a specific argument set, you can use Isolate.Verify.WasCalledWithExactArguments() - this accomplishes exactly that. Custom verification (for instance your string.Contains() verification delegate below) is a bit more complex and solved in version 5.3.5, as you noted.

In case you absolutely can't upgrade, you can use WhenCalled().DoInstead() to perform your own call logging and assert - I don't recommend this approach as it mixes up your Arrange and Assert stages. Let's see a code example:
var calledArguments = new List<string>();
// set up calls to Log() to record arguments
Isolate.WhenCalled(() => logger.Log(null)).DoInstead(
    context => 
    {
        var argument = (string)context.Parameters[0];
        calledArguments.Add(argument);
    });

// call the method under test
var target = new Foo();
target.SomeMethod();

// assert that a specific argument has been received
bool result = Array.Exists(calledArguments.ToArray(), logLine => logLine.Contains("message with");
Assert.IsTrue(result);


Please let me know if one of these tips help.

Doron
Typemock Support
answered by (16.5k points)
0 votes
Hi Doron,

Thanks for the reply.

I was able to do achieve what I was looking for using the below

Isolate.WhenCalled((string m) => logger.Error(m))
  .AndArgumentsMatch(m =>
  {
    if (m.Contains("substring I'm looking for"))
    {
      actualMessage = m;
      return true;
    }
    else
    {
      return false;
    }
  })
  .IgnoreCall();

// Do the actual call...

// Cheat and use the saved message from the WhenCalled method
Isolate.Verify.WasCalledWithExactArguments(() => logger.Error(actualMessage));


But I was actually really hoping that I was just missing an API call using Natural mocks. Sounds like I wasn't :(

Would the Reflective mocks support this??

Thanks again,

Carlos[/code]
answered by (2.8k points)
0 votes
Hi Carlos,

Reflective mocks API will not give you more power in this case.
Actually The DoInstead method is just for these kind of cases where you have a special kind of logic where the API does not cover.
answered by (35.5k points)
...