Using moq to verify a call to a function with param parameters - c#

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.

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.

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.

You could try to use the Callback, but it get fairly convoluted (not tested):
var mock = new Mock<ILogger>();
string trace = null;
mock.Setup(l => l.LogTrace(It.IsAny<string>(), It.IsAny<object[]>()))
.Callback((s1, par) =>
{
trace = string.Format(s1, par);
});
//rest of the test
Assert.AreEqual(expected, trace);
If ILogger has a small interface, you might consider implementing a stub manually (that would keep all the lines it is supposed to log), and verify that at the end of the test. If you have multiple lines being logged than this will be a more readable setup.

Related

How do I get NSubstitute mocks to fail when the arguments don't match the given pattern?

I'm responsible for the testing of a legacy software developed in C and C# that my team is maintaining. The original team used NSubstitute 3.1 to create test doubles for delegates in order to perform unit test of the APIs for the C# sections. Here's one such test double, where irrelevant details have been omitted:
private static byte[] MockSelectByAidWithoutData(ushort retVal)
{
var expectedIn= "FFFEFDFCFB".HexToBytes();
var expectedOut= "010203040506070809".HexToBytes();
var fake = Substitute.For<SomeDelegate>();
fake(Arg.Is<byte[]>(x => expectedIn.SequenceEqual(x.Take(expectedIn.Length))),
Arg.Is(0x00),
Arg.Is(expectedIn.Length),
Arg.Any<int>(),
Arg.Any<int>(),
out int outputLength)
.Returns(x =>
{
expectedOut.CopyTo((Array)x[0], 0);
x[5] = expectedOut.Length;
return retVal;
}
);
Mediator.GetInstance().Delegate = fake;
return expectedOut;
}
Now, if the fake delegate is invoked with arguments that match what is specified in the fake() call, it returns the retVal value and everybody is happy. However, if some value won't match, it returns zero. Since zero is a valid but incorrect value, the execution continues and I get an error that is not the root cause of the issue I am testing (i.e. bad output when the problem is actually bad input)
I am looking for a way to either:
specify a "catch all" behaviour for the values that won't match the expectations, or
get an exception if the arguments don't match the expectation
so that the test case would fail immediately upon reception of the wrong input with a meaningful message and without triggering further behaviour that would just pollute the outcome of the test.
Thanks in advance,
DeK
P.S. I can probably switch safely to a more recent version of NSubstitute if that's really necessary.
specify a "catch all" behaviour for the values that won't match the expectations
I think I've found a way you can do this. If you first stub the "catch all" / failure case for all arguments, you can then stub more specific calls. NSubstitute will try to match the most recent specifications provided, falling back to earlier stubbed values.
Here is a sample.
Note it is using Configure from NSubstitute.Extensions namespace introduced in NSubstitute 4.x. This isn't strictly necessary because NSubstitute will automatically assume you are configuring a call if you are using argument matchers, but it is a good pattern to use when configuring overlapping calls like this.
using NSubstitute;
using NSubstitute.Extensions; // required for Configure()
public class Thing {
public string Id { get; set; }
}
public interface ISample {
int Example(Thing a, string b);
}
public class UnexpectedCallException : Exception { }
[Fact]
public void ExampleOfStubOneCallButFailOthers() {
var sub = Substitute.For<ISample>();
// Catch all case:
sub.Example(null, null).ReturnsForAnyArgs(x => throw new UnexpectedCallException());
// Specific case. We use Configure from NSubstitute.Extensions to
// be able to stub this without getting an UnexpectedCallException.
// Not strictly necessary here as we're using argument matchers so NSub
// already knows we're configuring a call, but it's a good habit to get into.
// See: https://nsubstitute.github.io/help/configure/
sub.Configure()
.Example(Arg.Is<Thing>(x => x.Id == "abc"), Arg.Any<string>())
.Returns(x => 42);
// Example of non-matching call:
Assert.Throws<UnexpectedCallException>(() =>
sub.Example(new Thing { Id = "def" }, "hi")
);
// Example of matching call:
Assert.Equal(42, sub.Example(new Thing { Id = "abc" }, "hello"));
}
You could extend this to include information about arguments that do not match, but that will be a bit of custom work. If you look at some of NSubstitute's argument formatting code that might be re-usable to help with this.
Update to include delegate example
I just ran this with a delegate instead and it also passes:
public delegate int SomeDelegate(Thing a, string b);
[Fact]
public void ExampleOfStubOneDelegateCallButFailOthers() {
var sub = Substitute.For<SomeDelegate>();
sub(null, null).ReturnsForAnyArgs(x => throw new UnexpectedCallException());
sub.Configure()
.Invoke(Arg.Is<Thing>(x => x.Id == "abc"), Arg.Any<string>())
.Returns(x => 42);
Assert.Throws<UnexpectedCallException>(() => sub(new Thing { Id = "def" }, "hi"));
Assert.Equal(42, sub(new Thing { Id = "abc" }, "hello"));
}

Moq Setup with function that accepts a list of objects, how to define object Ids that can be accepted?

I have the below Moq service. One of the functions accepts various parameters but one of them is a List<MyObject> where MtObject has an Id. I have tried to define the actual object that the Moq should accept in order to return what I want returned for that object but it doesn't work - nothing is being returned - I'm wondering if it is because the object supplied isn't the exact object used when we call the Moq service - so I was going to try specifying the MyObject.Id in the setup but I can't figure out how to do it.
This was my original:
myService.Setup(s => s.GetSomeStuff(
It.IsAny<Reference>(),
new List<MyObject>() { fakeMyObject1, fakeMyObject2 },
anotherThing,
number))
.Returns(MyResponse).Verifiable();
The above returns null, if I use It.IsAny<List<MyObject>>() then I get a response but I need to have a different response based on the MyOject passed in.
What would I replace this line with in order to specify the fakeObject1.Id and fakeObject2.Id rather than the object?
new List<MyObject>() { fakeMyObject1, fakeMyObject2 }
Or do you think the original solution should work? Or is there another alternative?
I'm wondering if it is because the object supplied isn't the exact object used when we call the Moq service
That is correct. Because the argument instances do not match the mock wont behave as desired.
Use the It.Is<T>() argument matcher with a predicate to match the desired Ids
myService.Setup(_ => _.GetSomeStuff(
It.IsAny<Reference>(),
It.Is<List<MyObject>>(x =>
x.Any(y => y.Id == fakeObject1.Id || y.Id == fakeObject2.Id) //<-- or something else
),
anotherThing,
number))
.Returns(MyResponse)
.Verifiable();
Reference Moq Quickstart: Matching Arguments

Is there a technique for using DebugFormat() with args that are expensive to construct?

I'm a big fan of log4net and log4j's "format" API for logging messages, which avoids the cost of calling ToString() on arguments if the necessary log level is not enabled.
But there are times when one or more of the arguments I'd use is not a simple object, it needs to be constructed in some way. For example, like this:
logger.DebugFormat("Item {0} not found in {1}",
itemID,
string.Join(",", items.Select(i => <you get the idea>))
);
Is there a technique to encapsulate the second argument (the Join expression) such that it won't be executed unless DebugFormat decides that it should be (like it does for the ToString of the first argument)?
It feels like a lambda or func or something should be able to help here, but I'm fairly new to C# and I can't quite put my finger on it.
You can create extension method or wrapper class, but it's not easy to get satisfying syntax, because you want some parameters (itemID in your example) to be stated explicitly, and some to be resolved only if necessary. But you cannot pass anonymous function as object. Instead I'd use another solution which does not require extension methods or wrappers. Create class like this:
public sealed class Delayed {
private readonly Lazy<object> _lazy;
public Delayed(Func<object> func) {
_lazy = new Lazy<object>(func, false);
}
public override string ToString() {
var result = _lazy.Value;
return result != null ? result.ToString() : "";
}
}
This accepts function which returns object in constructor and will not call this function until ToString() is called, which as you know is called by log4net only if necessary (if such debugging level is enabled). Then use like this:
logger.DebugFormat("Item {0} not found in {1}",
itemID,
new Delayed(() => string.Join(",", items.Select(i => <you get the idea>)))
);

Can I reuse It.Any argument descriptors in Moq

I have some code similar to
FooMock.Setup( m => m.Bar( It.Is<BarArg>( x => long_test_x_is_ok(x) ) );
naively, I thought I could rewrite this as:
var barArg = It.Is<BarArg>( x => long_test_x_is_ok(x) );
FooMock.Setup( m => m.Bar( barArg ) );
but Moq doesn't love me. Is there a may to do this?
Similarly, some of our class names are quite long. I'd like to refactor the calls to
It.IsAny<AnnoyinglyLongClassNameHere>()
into something shorter
var anyAlcnh = It.IsAny<AnnoyinglyLongClassNameHere>;
doesn't seem to work either.
The reason it does not work is Setup is actually taking in a Expression<Action<IFoo>> not just a Action<IFoo>.
It never actually calls the Action you passed in, what it does is it takes the expression, pulls it apart and parses each component piece. Because of that you can't pull out barArg because that would make barArg a "black box" to the expression parser and would not know what the variable represents.
The best you could do is
//Assuming Bar has the signature "void Bar(BarArg barArg)".
//If it was "Baz Bar(BarArg barArg)" use "Expression<Func<IFoo, Baz>>" instead.
Expression<Action<IFoo>> setup = m => m.Bar(It.Is<BarArg>(x => long_test_x_is_ok(x)));
FooMock.Setup(setup);
The IsAny has the same problem, however for that you could make an alias to shorten the class name.
//At the top of your file with your other using statements
using ShortName = Some.Namespace.AnnoyinglyLongClassNameHere;
//Down in your unit test
FooMock.Setup(m => m.Bar(It.IsAny<ShortName>());

Evaluating a set of rules defined in a string

I made a system that creates a simple string with Function/Response format, example:
Check('Value'):ShowImage(#)|Check('Value'):OtherFunction(#)....and so on
Where Check is the name of a function, Value is the parameter, ShowImage is the name of a Response function, # is the entry paremeter (result of the previous function). The pipe splits another Function/Response pair that fires if the first Check('Value') function once "checked" were not satisfied (say, if the parameter was not accomplished the Check condition the function is invalid and hence the Response part in the first Function/Response pair is not executed, so system keep trying Functions awaiting to find the one that executes the right Response).
The way the application should work is to evaluate each rule (similar to a JavaScript eval function) and take appropriate action based on function results.
At first glance, it looks complicated, because first of all I need to cast the string to the right real C# function that will actually process the condition. Therefore, depending on the function result, decide where to point to execute my Response function.
Furthermore: This is just the kind example, because there are functions as * that represent something like: "any condition is true" what in almost all cases this function is the last in the chain (the default function).
That's my problem, I can't realize what is the easiest way to cope with this problem.
Maybe a chain of delegates? Lambdas? Anonymous stored into a structure...
Could you give me your measure/advise? Where to start?
Depending on the level of extensibility you want to have, I would say the most extensible way would be to use reflection to get method references, after you have parsed the input string.
You can start by splitting your problem into smaller subproblems.
Let's say you are aiming for something like this:
static void Main(string[] args)
{
string rules =
"Check(Morning):Say(Good morning)|" +
"Check(Afternoon):Say(Good afternoon)|" +
"Check(Evening):Say(Good night)";
// next, you need some **object instances** which will
// provide a context for your "test" and "action" methods.
// you don't want to use static methods if you
// went through the pain of defining such an architecture!
// let's say that a "Tester" object has a "Check" method,
// and an "Executor" object has a "Say" method:
var tester = new Tester("Afternoon");
var executor = new Executor();
// since I suck at regular expressions,
// I am using plain string methods to split
// the expression into tokens. You might want
// to add some validation
foreach (var rule in rules.Split('|'))
{
var result = Parse(rule, tester, executor);
if (result.TestPassed)
{
result.Execute();
break;
}
}
}
A "result" as it's used above would then have an interface like this:
public interface IResult
{
// returns true if a test is fulfilled
bool TestPassed { get; }
// executes the related action
void Execute();
}
And, if you want to delegate actual actions to some unknown methods, a reasonable way to implement it would be something like this:
public class Result : IResult
{
#region IResult Members
private readonly Func<bool> _testMethod;
public bool TestPassed
{
get { return _testMethod(); }
}
private readonly Action _actionMethod;
public void Execute()
{
_actionMethod();
}
#endregion
public Result(Func<bool> testMethod, Action actionMethod)
{
_testMethod = testMethod;
_actionMethod = actionMethod;
}
}
What's left is to use some reflection to get the actual methods out of your strings:
private static IResult Parse(string rule, object tester, object executor)
{
// split into test/action
var tokens = rule.Split(':');
// extract the method/parameter part for each expression
var test = GetMethodAndParams(tokens[0]);
var action = GetMethodAndParams(tokens[1]);
// use reflection to find actual methods
var testMethod = tester.GetType().GetMethod(test.Method);
var actionMethod = executor.GetType().GetMethod(action.Method);
// return delegates which will simply invoke these methods
return new Result
(
() => (bool)testMethod.Invoke(tester, new object[] { test.Param }),
() => actionMethod.Invoke(executor, new object[] { action.Param })
);
}
That is, more or less, your program's skeleton. You should be able to fill in the missing parts yourself, as an exercise. If you have problems, I can update the answer later.
A GetMethodAndParams method should split the input string into a Tuple (or your custom class) which contains the method name and its params as plain strings. Tester and Executor classes can also be implemented trivially.
It looks like you want a pattern along the lines of the .NET TryParse() methods. In that case, you would modify your check method to have an out parameter that is the value (represented in your example by #).
int result;
if(Check('Value', out result))
ShowImage(result);
else(Check('Value2', out result))
OtherFunction(result);
Finally I'm back here to post what I've done few weeks ago to solve this situation.
It was easy.
Regex class provide few options, one of those is "Explicit Catpure", all streams with the form (?) can be handled as strong typed parameters so, if the named group "IsNotEmptyorNull" then the function is present and it is promotable to casting using the form Enum.Parse("").
Snipet:
Regex rx = new Regex(#"(?<function>Check|BooleanOp)\('(?<param>[\w]+)'\){1}:(?<action>[\w]+){1}", RegexOptions.ExplicitCapture);
Match m;
Dictionary<FunctionArray, String> actions = new Dictionary<FunctionArray, String>();
if((m=rx.Match(strStream)).Success)
{
actions.Add((FunctionArray)Enum.Parse(typeof(FunctionArray), m.Groups["function"].value, true), m.Groups["param"].value);
}
Of course, there are lost the action part so I've improved the Dictionary stuff with an specialized Struct that can handle the functions and values as a source for decision taking.
Thanks to all. Ed.

Categories