模拟"系统控制台"行为



是否有一种标准的方法可以使c#控制台应用程序通过接口而不是System.Console进行单元测试?

例如,使用IConsole接口?

你这样做了吗?你用了什么样的方法?

当应用程序需要写入标准输出时,您是否公开事件?

我认为你的接口方法会工作,我不认为我会利用事件。假设应用程序不接受除命令行参数以外的用户输入,我可能会使用以下内容来包装Console.Write/Console.WriteLine:

public interface IConsoleWriter
{
    void Write(string format, params object[] args);
    void WriteLine(string format, params object[] args);
}
要进行测试,我可以创建一个TestConsoleWriter,它将所有写操作存储到一个缓冲区中,然后我可以对其进行断言;或者创建一个模拟,并验证是否使用我期望的参数调用了WriteWriteLine。如果您的应用程序将对控制台进行大量写入操作(例如+100 MB左右的输出),那么出于性能原因,使用mock可能是更可取的,但除此之外,我建议您选择您认为更容易使用的方法。 然而,这种方法确实有一些限制。如果您正在使用任何无法修改的程序集,并且它们写入控制台,那么您将看不到该输出,因为您无法强制这些类使用IConsoleWriter。另一个问题是WriteWriteLine方法有18个左右的重载,所以你可能包装了很多方法。为了绕过这些限制,您可能只需要在测试时使用Console.SetOut方法将控制台输出重定向到您自己的TextWriter

就我个人而言,我认为我会采取SetOut方法。这将只是你必须在单元测试开始时添加的一行(或可能在SetUp方法中),你可以断言写在TextWriter中的内容。

您想要更改控制台在单元测试中写入的流。然后你可以放入一个模拟流或其他东西。查看Mark Seemann关于测试控制台的帖子:

http://blogs.msdn.com/b/ploeh/archive/2006/10/21/consoleunittesting.aspx

我昨晚碰巧遇到了这个问题:在c#中使用反射来覆盖虚拟方法表。

@paul想出了答案:Philip Laureano的LinFu。

Philip Laureano的开发博客中的使用示例:Intercepting Console。WriteLine通过一个示例指导您如何拦截对控制台的调用。WriteLine方法,并且(在本例中)还执行一些附加操作…面向。net的AOP…非常注意,IMHO!

LinFu可能只是一个票子,因为它不存在于被拦截的东西中,所以你可以"拦截和修改"调用到第三方供应商的程序集的行为"在你的上下文中",但没有任何可能影响在上下文中被拦截的类的实际行为…所以LinFu听起来像是一个开始实施"主机应用通用测试框架"的好地方。

你甚至可以利用现有的单元测试框架之一。我会寻找一个开源框架。我立刻想到了NUnit。双关语。

祝你好运,这是一个有趣的项目。随时通知我们,K?

欢呼。基斯。

我建议使用痣

主要是因为我更喜欢让设计决定接口和类,而不是让测试

如果您只使用一个线程,则此代码将工作:

[TestClass]
public class MyTests
{
    private StringBuilder output;
    private StringWriter tempOutputWriter;
    private TextWriter originalOutputWriter;
    [TestInitialize]
    public void InitializeTest()
    {
        this.originalOutputWriter = Console.Out;
        this.tempOutputWriter = new StringWriter();
        Console.SetOut(tempOutputWriter);
        this.output = tempOutputWriter.GetStringBuilder();
    }
    [TestCleanup]
    public void CleanupTest()
    {
        Console.SetOut(originalOutputWriter);
        this.tempOutputWriter.Dispose();
    }
    [TestMethod]
    public void Test1()
    {
        Program.Main(new string[] { "1", "2", "3" });
        string output = this.output.ToString();
        ...
        this.output.Clear();
    }
    [TestMethod]
    public void Test2()
    {
        Program.Main(new string[] { "4", "5", "6" });
        string output = this.output.ToString();
        ...
        this.output.Clear();
    }
}

最新更新