Reputation: 6739
I am using Moq to verify if a method is being called in my unittest. In this specific case I want to test if the method under test logs an Error through log4net. The problem is, this can be done by either calling log.Error
or log.ErrorFormat
. Either is fine.
How can I verify this though? I only know how to verify that they have both been called.
var logMock = new Mock<ILog>();
var myClass = new MyClass(logMock.Object);
myClass.MyMethod();
logMock.Verify(log => log.Error(It.IsAny<object>()));
logMock.Verify(log => log.ErrorFormat(It.IsAny<string>(), It.IsAny<object>()));
Now that I think of it, they both have a bunch of overloads, I don't mind if any of the overloads are called either (I'm starting to doubt this is a good test).
Thanks in advance.
EDIT: I just thought of something nasty:
try
{
logMock.Verify(log => log.Error(It.IsAny<object>()));
}
catch (Moq.MockException ex)
{
logMock.Verify(log => log.ErrorFormat(It.IsAny<string>(), It.IsAny<object>()));
}
Maybe I can wrap this in some kind of extension method... e.g. VerifyAny
.
Upvotes: 13
Views: 2595
Reputation: 7493
You could register a callback for each valid error method that sets a flag:
// Arrange
bool errorFlag = false;
logMock
.Setup(l => l.Error(It.IsAny<object>()))
.Callback((object o) => errorFlag = true);
/* repeat setup for each logMock method */
// Act
myClass.MyMethod();
// Assert
Assert.IsTrue(errorFlag);
Of course, this will still be tedious if you have many overloads to cover.
EDIT: And for fun, here's an extension method for Mock<T>.VerifyAny
:
public static class MockExtensions
{
public static void VerifyAny<T>(this Mock<T> mock, params Expression<Action<T>>[] expressions)
where T: class
{
List<MockException> exceptions = new List<MockException>();
bool success = false;
foreach (var expression in expressions)
{
try
{
mock.Verify(expression);
success = true;
break;
}
catch (MockException ex)
{
exceptions.Add(ex);
}
}
if (!success)
{
throw new AggregateException("None of the specified methods were invoked.", exceptions);
}
}
}
Usage:
[TestMethod]
public void FooTest()
{
Mock<IFoo> fooMock = new Mock<IFoo>();
fooMock.Object.Bar1();
fooMock.VerifyAny(
f => f.Bar1(),
f => f.Bar2());
}
Upvotes: 18
Reputation: 14944
if you are specifically testing that a specific error was logged, why not have 2 tests, one that ensure that log.Error
is called and one that ensure that log.ErrorFormat
is called, I am assuming that you can control which one is called based on the input.
if you still wanna verify one or the other, you can just use this approach, it does exactly what you need:
Verify that either one method or the other was invoked in a unit test
Upvotes: 1