【问题标题】:Is it possible to test a function that only writes a line to the console? [closed]是否可以测试只向控制台写入一行的功能? [关闭]
【发布时间】:2020-04-03 17:53:15
【问题描述】:

是否可以测试一个返回 void 的函数,并且只使用 FluentAssertion 向控制台写入一行,如下所示?

static void WriteLine()
{
    Console.WriteLine("It works!");
}

【问题讨论】:

  • “测试”是什么意思?你的意思是写一个单元测试?如果您尝试从单元测试中记录某些内容,我建议您写入测试上下文。
  • 我的意思是为函数WriteLine(如上所示)编写一个单元测试,而不是从测试中记录一些东西。
  • 是否希望单元测试验证消息已打印到控制台?
  • @RogerioSchmitt 你为什么要这样?

标签: c# asp.net-core tdd fluent-assertions


【解决方案1】:

如果你想对这样的事情进行单元测试,你需要将你想要验证调用的方法提取到接口中。

然后将该接口传递给需要使用它的类,而不是让类直接调用实现(在本例中为Console.WriteLine())。这称为“依赖注入”。

因此,对于您的示例,您将发明以下接口:

public interface IConsole
{
    void WriteLine(string text);
}

您的真实代码将传递IConsole 的以下具体实现的实例:

public sealed class MyConsole : IConsole
{
    public void WriteLine(string text)
    {
        Console.WriteLine(text);
    }
}

但是,在测试您的课程时,您将通过 IConsole 的特殊测试实现。

假设您有以下使用IConsole 接口的类:

public class UnderTest
{
    public UnderTest(IConsole console)
    {
        _console = console;
    }

    public void WriteLine()
    {
        _console.WriteLine("It works!");
    }

    readonly IConsole _console;
}

注意IConsole 是如何传递给构造函数的——这被称为“构造函数注入”。

现在,您想测试一下,当您调用 UnderTest.WriteLine() 时,它会调用 IConsole.WriteLine("It works!");。

为此,首先使用a mocking framework such as Moq模拟IConsole接口:

var mock = new Mock<IConsole>();

然后构造一个你想测试的类的实例,将模拟的IConsole传递给它:

var underTest = new UnderTest(mock.Object);

现在你可以调用你期望调用的方法IConsole.WriteLine("It works!"):

underTest.WriteLine();

最后你可以验证IConsole.WriteLine("It works!")被调用了:

mock.Verify(x => x.WriteLine("It works!"));

将所有这些放在一个控制台应用程序中:

using System;
using Moq;

namespace Demo
{
    public interface IConsole
    {
        void WriteLine(string text);
    }

    // Not used but included as an example implementation.

    public sealed class MyConsole : IConsole
    {
        public void WriteLine(string text)
        {
            Console.WriteLine(text);
        }
    }

    public class UnderTest
    {
        public UnderTest(IConsole console)
        {
            _console = console;
        }

        public void WriteLine()
        {
            _console.WriteLine("It works!");
        }

        readonly IConsole _console;
    }

    public class Program
    {
        public static void Main()
        {
            var mock = new Mock<IConsole>();
            var underTest = new UnderTest(mock.Object);

            underTest.WriteLine();

            mock.Verify(x => x.WriteLine("It works!"));
        }
    }
}

(请注意,要编译它,您需要安装 Moq。)

我没有在此示例中使用 FluentAssertions,但您可以将它们与 Moq 一起使用,尽可能多或尽可能少。

【讨论】:

    【解决方案2】:

    您应该不具有向控制台写入一行的函数。

    您应该有一个函数,该函数将一行写入System.IO.TextWriter 作为参数传递给它。

    在生产代码中,您向此函数传递了对 System.Console.Out 的引用,因此它的行为类似于“向控制台写入一行的函数”。

    从测试代码中,您将System.IO.StringWriter 的实例传递给它,这样您就可以检查它写入的内容。

    这是一个众所周知的依赖注入概念的应用,它对于编写可测试的代码是绝对必要的。在您所做的一切事情中使用它。

    维基百科:Dependency injection

    【讨论】:

      【解决方案3】:

      您可以通过监控标准输出来实现这一点(它是处理所有软件输出的操作系统级流)。

      如果您实现了类似于示例 here 的内容并监控了最新的输出,那么您可以对这些最重要的消息使用断言来确定您的应用程序是否正常运行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-02
        相关资源
        最近更新 更多