在单元测试中检查控制台输出

Gue*_*lla 4 c# testing nunit unit-testing moq

有没有办法可以检查抽象类问题的单元测试中控制台的输出是什么?

我正在使用 NUnit 和 Moq。

我的单元测试如下所示:

    [Test]
    public void QuestionAsk()
    {
        var mock = new Mock<Question>(new object[]{"question text",true});

        mock.CallBase = true;

        var Question = mock.Object;

        Question.Ask();

        mock.Verify(m => m.Ask(), Times.Exactly(1));

    }
Run Code Online (Sandbox Code Playgroud)

在这里,我检查 Question.Ask() 是否被调用并且工作正常。Ask() 不返回值,因此我无法将其分配给变量。该函数仅输出到控制台。

有没有办法在测试中验证输出==“问题文本”?

编辑:忘记提及 Question 是一个抽象基类。

我尝试了使用此代码建议的 Concole.Setout 方法:

    [Test]
    public void QuestionAsk()
    {
        var mock = new Mock<Question>(new object[]{"question text",true});

        mock.CallBase = true;

        var Question = mock.Object;

        using (var consoleText = new StringWriter())
        {
            Console.SetOut(consoleText);
            Question.Ask();
            Assert.That(consoleText.ToString(), Is.StringMatching("question text"));
        }
        mock.Verify(m => m.Ask(), Times.Exactly(1));

    }
Run Code Online (Sandbox Code Playgroud)

但花费了 236 毫秒,这对于测试来说太长了。实现 IWriter 接口似乎是处理这个问题的最佳方法,所以我现在就尝试一下。

Kei*_*yne 5

您可以Question使用自定义输出编写器进行初始化,然后模拟编写器以验证输出:

public interface IOutputWriter 
{
    void WriteLine(string s);
}

// Use this console writer for your live code
public class ConsoleOutputWriter : IOutputWriter
{
    public void WriteLine(string s)
    {
        Console.WriteLine(s);
    }
}

public abstract class Question
{
    private readonly IOutputWriter _writer;
    private readonly string _text;
    private readonly bool _default;

    public Question(IOutputWriter writer, params object[] args)
    {
        _writer = writer;
        _text = (string)args[0];
        _default = (bool)args[1];
    }

    public void Ask()
    {
        _writer.WriteLine(_text);
    }
}


[Test]
public void QuestionAsk()
    {
        var writer = new Mock<IOutputWriter>();

        var mock = new Mock<Question>(writer.Object, new object[]{"question text",true});

        mock.CallBase = true;

        var Question = mock.Object;

        Question.Ask();

        mock.Verify(m => m.Ask(), Times.Exactly(1));
        mock.Verify(w => w.WriteLine(It.Is<string>(s => s == "question text")), Times.Once)

    }
Run Code Online (Sandbox Code Playgroud)