是否可以测试只向控制台写入一行的函数?

Rog*_*itt -1 c# tdd fluent-assertions asp.net-core

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

static void WriteLine()
{
    Console.WriteLine("It works!");
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*son 8

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

Then you pass that interface to the classes that need to use it, rather than having the classes call the implementation (in this case, Console.WriteLine()) directly. This is called "dependency injection".

So for your example, you'd invent the following interface:

public interface IConsole
{
    void WriteLine(string text);
}
Run Code Online (Sandbox Code Playgroud)

Your real code would be passed an instance of the following concrete implementation of IConsole:

public sealed class MyConsole : IConsole
{
    public void WriteLine(string text)
    {
        Console.WriteLine(text);
    }
}
Run Code Online (Sandbox Code Playgroud)

However, when testing your class you would pass it a special test implementation of IConsole.

Let's suppose you have the following class that uses the IConsole interface:

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

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

    readonly IConsole _console;
}
Run Code Online (Sandbox Code Playgroud)

Note how the IConsole is passed to the constructor - this is known as "constructor injection".

Now, you want to test that when you call UnderTest.WriteLine() it calls IConsole.WriteLine("It works!");.

为此,首先使用Moq 等模拟框架来模拟IConsole接口:

var mock = new Mock<IConsole>();
Run Code Online (Sandbox Code Playgroud)

然后构造要测试的类的实例,将模拟的内容传递给它IConsole

var underTest = new UnderTest(mock.Object);
Run Code Online (Sandbox Code Playgroud)

现在您可以调用您希望调用的方法IConsole.WriteLine("It works!")

underTest.WriteLine();
Run Code Online (Sandbox Code Playgroud)

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

mock.Verify(x => x.WriteLine("It works!"));
Run Code Online (Sandbox Code Playgroud)

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

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!"));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

我没有FluentAssertions在这个例子使用它们,但是你可以Moq根据需要尽可能多地或尽可能少地使用它们。


Mik*_*kis 5

你应该不会有写一行到控制台的功能。

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

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

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

这是众所周知的依赖注入概念的应用,对于编写可测试的代码来说绝对是必不可少的。在你所做的一切中使用它。

维基百科:依赖注入