如果你想对这样的事情进行单元测试,你需要将你想要验证调用的方法提取到接口中。
然后将该接口传递给需要使用它的类,而不是让类直接调用实现(在本例中为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 一起使用,尽可能多或尽可能少。