I have an interface:
public interface IRepeater
{
void Each(string path, Action<string> action);
}
I want to mock this interface using Moq
. Now I can obviously do the following:
var mock = new Mock<IRepeater>();
mock.Setup(m => m.Each(It.IsAny<string>(), It.IsAny<Action<string>>());
However, to aid testing I want to be able to mock the string
that gets passed to the Action<string>
. Can this be done with Moq
? If yes, how?
To clarify I am testing a different class
that has a dependency on IRepeater
. I want to mock IRepeater.Each
so I can control the string
that the Action
gets so I can test the behaviour.
So if I have a class
like so.
public class Service
{
private readonly IRepeater _repeater;
public Service(IRepeater repeater)
{
_repeater = repeater;
}
public string Parse(string path)
{
var builder = new StringBuilder();
_repeater.Each(path, line => builder.Append(line));
return builder.ToString();
}
}
How do I mock IRepeater.Each
so that I can test Service.Parse
?
You have to use callback
method. Since line => builder.Append(line)
is part of the method behavior, you have to execute this behavior when you test the method:
[TestMethod]
public void Test_Service_When_Passing_String_And_ActionDelegate()
{
var fakeReporter = new Mock<IRepeater>();
fakeReporter.Setup(x => x.Each(It.IsAny<string>(), It.IsAny<Action<string>>()))
.Callback<string, Action<string>>((s, action) => action(s));
var target = new Service(fakeReporter.Object);
var result = target.Parse("asdfghj");
Assert.AreEqual("asdfghj", result);
}
Another approach to test this method is to verify the method was called with the correct path and then verify that the action is the correct action:
[TestMethod]
public void Test_Service_When_Passing_String_And_ActionDelegate()
{
var fakeReporter = new Mock<IRepeater>();
fakeReporter.Setup(x => x.Each(It.IsAny<string>(), It.IsAny<Action<string>>()))
.Callback<string, Action<string>>((s, action) =>
{
Assert.AreEqual("asdfghj", s);
foreach (var w in "pass")
{
action(w.ToString());
}
});
var target = new Service(fakeReporter.Object);
var result = target.Parse("asdfghj");
Assert.AreEqual("pass", result);
}
BTW you can replace the It.IsAny<string>()
with the string and then remove the Assert.AreEqual("asdfghj", s);
(I just like to test things in the explicit way...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With