Как проверить, был ли вызван один из двух методов?

я использую Moq, чтобы проверить, вызывается ли метод в моем unittest. В этом конкретном случае я хочу проверить, регистрирует ли метод в тесте ошибку через log4net. Проблема в том, что это можно сделать, вызвав log.Error или log.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>()));

теперь, когда я думаю об этом, у них обоих есть куча перегрузок, я не возражаю, если какой-либо перегрузки называется либо (я начинаю сомневаться, что это хороший тест).

спасибо заранее.

EDIT: я просто подумал о чем-то неприятном:

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 ответов


вы можете зарегистрировать обратный вызов для каждого допустимого метода ошибки, который устанавливает флаг:

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

Если вы специально проверяете, что была зарегистрирована конкретная ошибка, почему бы не иметь 2 теста, которые гарантируют, что log.Error вызывается и тот, который гарантирует, что log.ErrorFormat вызывается, я предполагаю, что вы можете контролировать, какой из них вызывается на основе ввода.

Если вы все еще хотите проверить один или другой, вы можете просто использовать этот подход, он делает именно то, что вам нужно:

убедитесь, что один или другой метод был вызван в модульном тесте