如何验证是否已调用两种方法之一?

时间:2013-01-10 00:09:40

标签: c# unit-testing moq

我正在使用Moq来验证我的unittest中是否正在调用某个方法。在这种特定情况下,我想测试测试中的方法是否通过log4net记录错误。问题是,可以通过调用log.Errorlog.ErrorFormat来完成此操作。要么没事。

我如何验证这一点?我只知道如何验证它们都已被调用。

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>()));

现在我想到了,它们都有一堆重载,我不介意是否也调用了任何重载(我开始怀疑这是一个很好的测试)。

提前致谢。

编辑:我只是想到了一件令人讨厌的事情:

try
{
    logMock.Verify(log => log.Error(It.IsAny<object>()));
}
catch (Moq.MockException ex)
{
    logMock.Verify(log => log.ErrorFormat(It.IsAny<string>(), It.IsAny<object>()));
}

也许我可以用某种扩展方法包装它...例如VerifyAny

2 个答案:

答案 0 :(得分:12)

您可以为设置标志的每个有效错误方法注册回调:

// 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);

当然,如果你有很多重载要做,这仍然会很乏味。

编辑:为了好玩,这是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);
        }
    }
}

用法:

[TestMethod]
public void FooTest()
{
    Mock<IFoo> fooMock = new Mock<IFoo>();
    fooMock.Object.Bar1();

    fooMock.VerifyAny(
        f => f.Bar1(),
        f => f.Bar2());
}

答案 1 :(得分:1)

如果您专门测试是否记录了特定错误,为什么不进行2次测试,一次确保调用log.Error,另一次确保调用log.ErrorFormat,我假设您可以根据输入控制调用哪一个。

如果您仍想验证其中一种,您可以使用这种方法,它完全符合您的需要:

Verify that either one method or the other was invoked in a unit test

相关问题