首页 > 解决方案 > 为什么我的模拟记录器显示为已调用但也没有?

问题描述

我第一次尝试在 WPF 应用程序中进行模拟。我正在测试的代码是 MVVM ViewModel 方法的一部分,如下所示:

try
{
    var airframesForRegistration = this.UnitOfWork.Airframes.GetAirframesForRegistration(this.SearchRegistration);
    this.currentAirframes = new ObservableCollection<Airframe>(airframesForRegistration);
}
catch (Exception ex)
{
    this.logger.Error($"Could not access the database", ex);
    throw;
}

我想测试一下

  1. 错误被写入记录器服务并且
  2. 抛出异常。

为此,我使用了 XUnit 和 Moq:

[Fact]
public void GetAirframesForSearchRegistration_DBAccessFail()
{
    using (var mock = AutoMock.GetLoose())
    {
        mock.Mock<IUnitOfWork>()
            .Setup(x => x.Airframes.GetAirframesForRegistration("AAAA"))
            .Throws(new DataException());

        string message = "Could not access the database";
        DataException exception = new DataException();

        mock.Mock<ILog>()
            .Setup(x => x.Error(message, exception));

        var afrvm = mock.Create<AirframesForRegistrationViewModel>();

        afrvm.SearchRegistration = "AAAA";

        Assert.Throws<DataException>(() => afrvm.GetAirframesForSearchRegistration());

        mock.Mock<ILog>()
            .Verify(x => x.Error(message, exception), Times.Exactly(1));

    }

测试因此失败:

Message: Moq.MockException : 
Expected invocation on the mock exactly 1 times, but was 0 times: x => x.Error("Could not access the database'", System.Data.DataException: Data Exception.)

Configured setups: 
ILog x => x.Error("Could not access the database", System.Data.DataException: Data Exception.)

Performed invocations: 
ILog.Warn("No Operators found in the database")
ILog.Warn("No airframe statuses found in the database")
ILog.Error("Could not access the database", System.Data.DataException: Data Exception.
   at Moq.MethodCall.Execute(Invocation invocation) in C:\projects\moq4\src\Moq\MethodCall.cs:line 120

(注意额外的 ILog 警告出现在 ViewModel 的其他地方,我期待这些警告)。

问题

这意味着调用了错误日志记录,但测试失败了,因为它调用了零次!如何设置 Moq 和 XUnit 以正确测试这种情况?

标签: wpfexceptionloggingmoqxunit

解决方案


记录器参数的设置是问题所在。

抛出的实例和预期的实例不同意味着它们在调用模拟时不会匹配。

模拟工作单元正在抛出一个新异常。不是你期待的那个。

[Fact]
public void GetAirframesForSearchRegistration_DBAccessFail() {
    using (var mock = AutoMock.GetLoose()) {
        //Arrange
        DataException exception = new DataException();

        mock.Mock<IUnitOfWork>()
            .Setup(x => x.Airframes.GetAirframesForRegistration("AAAA"))
            .Throws(exception);

        string message = "Could not access the database";

        mock.Mock<ILog>()
            .Setup(x => x.Error(message, exception));

        var afrvm = mock.Create<AirframesForRegistrationViewModel>();

        afrvm.SearchRegistration = "AAAA";

        //Act
        Action act = () => afrvm.GetAirframesForSearchRegistration();

        //Assert
        Assert.Throws<DataException>(act);

        mock.Mock<ILog>()
            .Verify(x => x.Error(message, exception), Times.Exactly(1));
    }
}

对于更宽松的期望,您可以使用It.IsAny<>参数匹配器

[Fact]
public void GetAirframesForSearchRegistration_DBAccessFail() {
    using (var mock = AutoMock.GetLoose()) {
        //Arrange
        mock.Mock<IUnitOfWork>()
            .Setup(x => x.Airframes.GetAirframesForRegistration("AAAA"))
            .Throws(new DataException());

        string message = "Could not access the database";

        mock.Mock<ILog>()
            .Setup(x => x.Error(message, It.IsAny<DataException>()));

        var afrvm = mock.Create<AirframesForRegistrationViewModel>();

        afrvm.SearchRegistration = "AAAA";

        //Act
        Action act = () => afrvm.GetAirframesForSearchRegistration();

        //Assert
        Assert.Throws<DataException>(act);

        mock.Mock<ILog>()
            .Verify(x => x.Error(message, It.IsAny<DataException>()), Times.Exactly(1));
    }
}

推荐阅读