c# - 实现上的单元测试接口(interface)

标签 c# testing logging interface

我有一个用于获取一些数据的 MVC Controller 的接口(interface)。为了简单起见,目前的界面看起来像这样:

public interface IDataProvider
{
    DataModel GetData();
}

我对该接口(interface)进行了适当的单元测试,它在操作中被调用。然而,在实际实现中,这将调用一个 Web 服务,当然它可能会抛出异常,因此如果抛出异常,我想编写一个测试以确保在发生错误时记录一条消息。

为此,我有一个记录器接口(interface),它实际上是一个名为 ILogger 的 NLog 接口(interface)。我可以这样做:

public interface IDataProvider
{
    DataModel GetData(ILogger logger);
}

这将允许我为记录器运行单元测试,使其变得简单易用。但是,我不认为这是执行此操作的正确方法,因为记录器实际上与此方法无关。此外,如果我开始向该接口(interface)添加其他需要记录的方法,那么我还必须在所有这些方法的参数中包含记录器。

我现在能想到的最好方法是在我的实现的构造函数中包含记录器,它可能如下所示:

public class DataProvider : IDataProvider
{
    private readonly ILogger _logger;

    public DataProvider(ILogger logger)
    {
        _logger = logger;
    }

    public DataModel GetData()
    {
        // CODE GOES HERE
    }
}

然而,这意味着我无法在我的单元测试中测试记录器。实现此目的的最佳方法是什么,以便我可以将记录器与方法分开并使其可测试?

我会很感激任何帮助,谢谢。

编辑:

我意识到我错过了单元测试代码,这就是我的意思:

目前我正在确保以这种方式在我的操作中调用 GetData:

var controller = new DataController(_dataProvider.Object);

controller.Index();

_dataProvider.Verify(dataProvider => dataProvider.GetData());

我想做的是相同的,但对于记录器,但前提是像这样抛出异常:

_dataProvider.Setup(dataProvider => dataProvider.GetData()).Throws<WebException>();

var controller = new DataController(_dataProvider.Object);

controller.Index();

_logger.Verify(logger => logger.ErrorException(It.IsAny<string>(), It.IsAny<Exception>());

显然,记录器将在设置中提供给数据提供者。我希望这更有意义。

最佳答案

你可以尝试使用工厂模式。

这里发生的是在您的生产代码中,您正在从工厂 获取记录器。在这个工厂中,它返回您的真实记录器或在您的单元测试中设置的 记录器。对于您的生产代码,这没有任何区别。

在您的单元测试中,您使用的是使用 Moq 创建的虚假记录器.此伪造允许您测试是否调用了接口(interface)方法,在本例中为 ILogger.Log()。这是通过使用 .Verify 方法完成的。

尝试这样的事情:

ILogger.cs

public interface ILogger
{
    void Log(string message);
}

LoggerFactory.cs

public static class LoggerFactory
{
    public static ILogger Logger
    {
        get
        {
            return LoggerFactory._logger == null ? new Logger() : LoggerFactory._logger;
        }
        set
        {
            LoggerFactory._logger = value;
        }
    }
    private static ILogger _logger = null;
}

DataProvider.cs

public void GetData()
{
    var logger = LoggerFactory.Logger;

    logger.Log("..."); // etc...
}

UnitTest.cs

private void Mock<ILogger> _mockLogger = null;

public void Load()
{
    this._mockLogger = new Mock<ILogger>();

    LoggerFactory.Logger = _mockLogger.Object;
}

public void UnitTest()
{
    // test as required

    this._mockLogger.Verify(m => m.Log(It.IsAny<string>()));
}

关于c# - 实现上的单元测试接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15663593/

相关文章:

c# - Entity Framework Code First 和 SQL Azure 连接

c# - 来自类库的 HtmlEncode

PHPUnit - hasOutput() 不工作

python 多处理日志记录,根记录器在 windows 中不同

c# - 在滚动文件的顶部仅包含一次标题

c - 从 err(3) 函数创建日志文件

c# - 为什么 Web 服务引用和服务引用的结果不同?

testing - 属性文件阅读器是否在 jmeter 非 gui 模式下工作

git - 我可以在 git 中合成一个跳过单个更改集的分支吗

c# - 在没有 parent 的情况下使用平台旋转播放器