Substitute method in lambda expression - c#

I am writing unit tests for a series of similar methods defined on a single interface (this is a precursor to refactoring). I'm finding that similar code shows up in multiple methods:
// Each line here shows up in a different test method.
mock.Setup(m => m.MethodA()).Returns(() => true);
mock.Setup(m => m.MethodB()).Returns(() => true);
mock.Setup(m => m.MethodC()).Returns(() => true);
I would like to create a single method into which I can pass the method to be tested, but am at a loss how to do this. I'd like something that looks like this:
// testMethod is some method defined on IMyInterface.
private Mock<IMyInterface> SetupMockObject(Func<bool> testMethod)
{
var mock = new Mock<MyInterface>();
mock.Setup(m => m.testMethod()).Returns(() => true);
return mock;
}
The call to this method would then look something like:
var configuredMockObject = SetupMockObject(MethodA);
Is this possible?
EDIT: An expression tree appears to be what I need - previously I didn't get the concept that you could pass lambda expressions around. I've pasted the solution below since it took me a bit of fiddling to figure this out, although both dBurner's and Servy's answers proved helpful.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Moq.Language.Flow;
using System;
using System.Linq.Expressions;
namespace ExampleTest
{
[TestClass]
public class TestClass
{
private Mock<IMyInterface> _mock;
private interface IMyInterface
{
bool MethodA();
bool MethodB();
}
private ISetup<IMyInterface, bool> SetupMockObject(Expression<Func<IMyInterface,bool>> lambda)
{
var mockSetup = _mock.Setup(lambda);
return mockSetup;
}
[TestInitialize]
public void Setup()
{
_mock = new Mock<IMyInterface>();
}
[TestMethod]
public void TestMethodA()
{
SetupMockObject(i => i.MethodA()).Returns(true);
// Proceed with act and assert.
}
[TestMethod]
public void TestMethodB()
{
SetupMockObject(i => i.MethodB()).Returns(true);
// Proceed with act and assert.
}
}
}

The lambda that you pass to it needs to have a parameter of the mocked type, whereas your current parameter accepts a parameterless delegate:
public static Mock<MyInterface> SetupMockObject<T>(
Func<MyInterface, bool> testMethod)
{
var mock = new Mock<MyInterface>();
mock.Setup(testMethod).Returns(() => true);
return mock;
}
This allows you to write:
var mock = SetupMockObject(m => m.MethodA());
and have the code be equivalent to
var mock = new Mock<MyInterface>();
mock.Setup(m => m.MethodA()).Returns(() => true);

You can use expression trees for this. Your CommonTest method should have a Expression<Func<bool>> parameter.
With this parameter type you can get the method name. after this you should construct another Expression that will represent m => m.MethodFromParameter.

Related

Moq - Is it possible to setup a mock without using It.IsAny

I use Moq all the time for unit tests. Sometimes though I am mocking methods that have a lot of parameters.
Imagine a method like this:
public class WorkClient {
public void DoSomething(string itemName,
int itemCount,
ServiceClientCredential cred,
CancellationToken = default(CancellationToken){}
}
When I go to setup a mock, I end up having to do quite a lot of It.IsAny<T>(). I normally make one mocked instance per each test so I don't care about matching params.
But my mocks still look like this
var newMockClient = new Mock<WorkClient>();
newMockClient.Setup(x => x.DoSomething(
It.IsAny<string>(),
It.IsAny<int>(),
It.IsAny<ServiceClientCredential(),
It.IsAny<CancellationToken>())
.Returns(blah);
I would love to be able to just lazily instead use a LazySetup if it exists, like this.
newMockClient.Setup(x=>x.DoSomething()).Returns(blah);
Is there any lazy mode like this?
Based on this gist you can create an overload for SetupDefaultArgs which works well with void return type. You will need to add a reference to Moq.Language.Flow and System.Linq.Expressions;
public static ISetup<T> SetupDefaultArgs<T>(this Mock<T> mock, string methodName)
where T : class
{
var method = typeof(T).GetMethod(methodName);
if (method == null)
throw new ArgumentException($"No method named '{methodName}' exists on type '{typeof(T).Name}'");
var instance = Expression.Parameter(typeof(T), "m");
var callExp = Expression.Call(instance, method, method.GetParameters().Select(p => GenerateItIsAny(p.ParameterType)));
var exp = Expression.Lambda<Action<T>>(callExp, instance);
return mock.Setup(exp);
}
//helper method for above
private static MethodCallExpression GenerateItIsAny(Type T)
{
var ItIsAnyT = typeof(It)
.GetMethod("IsAny")
.MakeGenericMethod(T);
return Expression.Call(ItIsAnyT);
}
So, in your case the usage would look something like this:
public interface IWorkClient
{
void DoSomething(string itemName, int itemCount,
ServiceClientCredential cred,
CancellationToken token = default(CancellationToken));
}
var mock = new Mock<IWorkClient>();
mock.SetupDefaultArgs(nameof(IWorkClient.DoSomething));
To make sure that it has been called you can do the following:
//Arrange
var mock = new Mock<IWorkClient>();
mock.SetupDefaultArgs(nameof(IWorkClient.DoSomething))
.Callback(() => Console.WriteLine("DoSomething has been called"));
var cts = new CancellationTokenSource();
//Act
mock.Object.DoSomething("1", 2, null, cts.Token);
//Assert
mock.Verify(client => client.DoSomething("1", 2, null, cts.Token), Times.Once);

How to test if a function received a specific delegate using NSubstitute?

I would like to test if function received a specific delegate as parameter. Is it possible in NUnit with NSubstitute?
My interface:
public interface IMyInterface
{
void Sort(Func<IEnumerable<int>, IOrderedEnumerable<int>> f);
}
My test class:
[TestFixture]
public class Class1
{
[Test]
public void Sort_WhenCalled_CallsWithPassedArgument()
{
// Arrange
IMyInterface mock = Substitute.For<IMyInterface>();
// Act
mock.Sort(x => x.OrderBy(y => y));
// Assert
mock.Received().Sort(x => x.OrderBy(y => y));
}
}
I also tried with argument matchers, but it always fails.
The challenge is that your argument type is Func<>, not Expression<Func<>>. With Expression you could inspect the tree to check method names etc.
However, you can unit test against the concrete example for OrderBy (e.g. as opposed to OrderByDescending(), because given a collection of ints 6,4 OrderBy() will always re-sort it to be 4,6. So the following works:
[TestFixture]
public class Class1
{
[Test]
public void Sort_WhenCalled_CallsWithPassedArgument()
{
// Arrange
IMyInterface mock = Substitute.For<IMyInterface>();
Func<IEnumerable<int>, IOrderedEnumerable<int>> func = null;
mock.WhenForAnyArgs(x => x.Sort(Arg.Any<Func<IEnumerable<int>, IOrderedEnumerable<int>>>())).Do(
x =>
{
func = x.Arg<Func<IEnumerable<int>, IOrderedEnumerable<int>>>();
});
// Act
mock.Sort(x => x.OrderBy(y => y));
// Assert
var result = func(new[] { 6, 4 });
Assert.That(result.FirstOrDefault(), Is.Not.EqualTo(6));
Assert.That(result.FirstOrDefault(), Is.EqualTo(4));
}
}
Of course, the logic is somewhat fragile, so you need to decide if you really want to test that an exact method is used in a func (and then maybe refactor the code to allow to check for this specific method by other means or switch to Expression) or just the behaviour is enough for you.

How do I setup MOQ to accept Any instances of a given Expression<T>?

I have the following interface that I want to mock:
public interface ISomeInterface
{
string GiveMe(Expression<Func<Person, bool>> predicate);
}
With the following Poco:
public class Person
{
public string Name { get; set; }
}
Then I am setting up my mock as:
[Test]
public void Run()
{
var expectedPredicate = It.IsAny<Expression<Func<Person, bool>>>();
var mock = new Mock<ISomeInterface>(MockBehavior.Strict);
mock
.Setup(m => m.GiveMe(expectedPredicate))
.Returns("Yo!");
var message = mock.Object.GiveMe(p => p.Name == string.Empty); // throws
}
But I am getting:
Invocation failed with mock behavior Strict. All invocations on the
mock must have a corresponding setup.
What am I missing here?
Don't assign the result of It.IsAny to an intermediate variable, use it inline:
mock.Setup(m => m.GiveMe(It.IsAny<Expression<Func<Person, bool>>>()))
.Returns("Yo!");
If you look at the Setup method, it actually takes an Expression parameter, Moq analyses this to determine what your intention is, by assigning the result of It.IsAny to an intermediate variable, Moq will not see the MethodCallExpression it is capable of understanding and instead will see a MemberExpression.
This results in Moq actually performing an equality comparison between the actual parameter and expectedPredicate variable rather than the It.IsAny check.

Moq verify fails when SelectMany

I am using NUnit, Moq and StructureMap.
I have a following NUnit test:
[Test]
public void ShouldCallCustomMethod_ForAllICustomInterfaceMocks()
{
var customInterfaceMock1 = new Mock<ICustomInterface>();
var customInterfaceMock2 = new Mock<ICustomInterface>();
ObjectFactory.Inject(customInterfaceMock1.Object);
ObjectFactory.Inject(customInterfaceMock2.Object);
var sut = new SUT();
sut.MethodThatShouldCallCustomMethodOnMocks();
customInterfaceMock1.Verify(m => m.CustomMethod());
customInterfaceMock2.Verify(m => m.CustomMethod());
}
ICustomInterface:
public interface ICustomInterface
{
IEnumerable<Type> CustomMethod();
}
Now if implementation of SUT class looks like this:
public class SUT
{
public IEnumerable<Type> MethodThatShouldCallCustomMethodOnMocks()
{
var result = ObjectFactory.GetAllInstances<ICustomInterface>()
.SelectMany(i => i.CustomMethod());
return result;
}
}
test from above fails due to method CustomMethod not being called on mocks.
However, if I change implementation of SUT class to this:
public class SUT
{
public IEnumerable<Type> MethodThatShouldCallCustomMethodOnMocks()
{
var customInterfaceInstances = ObjectFactory.GetAllInstances<ICustomInterface>();
foreach (var instance in customInterfaceInstances)
instance.CustomMethod();
return ...
}
}
test passes!
The difference is that instead of iterating with SelectMany i use foreach, but test results differ (in second case CustomMethods do get called on mocks).
Can somebody explain that behaviour?
I think this might be a case of deferred execution. SelectMany doesn't execute immediately. The IEnumerable that's returned must be enumerated for your methods to be called. Try adding ToList() after the SelectMany() method to force the IEnumerable returned from SelectMany to be evaluated.

Faking a generic method FakeItEasy

How would you go about faking the following:
public interface IBlah
{
Func<T, bool> ApplyFilter<T>(Func<T, bool> predicate) where T:IMessage;
}
What I would like is for the fake to simply return it's argument without any changes. However, I would like to verify that the fake has been called exactly once. A use case is given below:
public class Something
{
public Something(IBlah blah) { _blah = blah; }
public bool DoSomething(SomeValue m, Func<SomeValue, bool> predicate)
{
Func<SomeValue, bool> handler = _blah.ApplyFilter(predicate);
return handler(m);
}
}
i.e. the fake needs to act as a pass through but I also need to be able to verify it's been used.
What's the best way to go about this?
[Please don't worry about the contrived example...there's a lot of things going on under the covers, but I've simplified it down to the example above.]
Would this solve your issue? It will pass through the predicate and also verify that ApplyFilter was called exactly once
[Fact]
public void TestFeature()
{
var fake = A.Fake<IBlah>();
A.CallTo(() => fake.ApplyFilter(A<Func<int, bool>>.Ignored)).ReturnsLazily(x =>
{
return x.GetArgument<Func<int, bool>>("predicate");
});
var something = new Something(fake);
var result = something.DoSomething(1, x => x > 1);
Assert.False(result);
A.CallTo(() => fake.ApplyFilter(A<Func<int, bool>>.Ignored)).MustHaveHappened(Repeated.Exactly.Once);
}

Categories