是否有一种标准的方法可以通过对接口而不是System.Console进行编程来使C#控制台应用程序单元可测试?
例如,使用IConsole接口?
你做过这个,你用过什么样的方法?
您是否公开了应用程序何时需要写入标准输出的事件?
答案 0 :(得分:14)
我认为你使用界面的方法会起作用,我认为我不会利用事件。假设应用程序不接受命令行参数以外的用户输入,我可能会使用这样的东西来包装Console.Write/Console.WriteLine
:
public interface IConsoleWriter
{
void Write(string format, params object[] args);
void WriteLine(string format, params object[] args);
}
为了测试,我要么创建一个TestConsoleWriter
,它将所有写入存储到我可以断言的缓冲区中,或者我会创建一个模拟并验证Write
或{{1}用我期望的参数调用。如果你的应用程序要对控制台进行大量的写操作(比如输出+100 MB左右),那么出于性能原因,使用模拟可能会更好,但除此之外我会说你选择哪种方法更容易使用。
然而,这种方法确实有一些限制。如果您正在使用任何无法修改的程序集并且它们写入控制台,那么您将无法看到该输出,因为您无法强制这些类使用您的WriteLine
。另一个问题是IConsoleWriter
和Write
方法有18个左右的重载,所以你可能会包含很多方法。要解决这些限制,您可能只想在测试时使用WriteLine
方法将控制台输出重定向到您自己的Console.SetOut
。
就个人而言,我想我会采用TextWriter
方法。它只需要在单元测试开始时添加一行(或者可能在SetOut
方法中),并且可以断言写入SetUp
的内容。
答案 1 :(得分:9)
您想要更改控制台在单元测试中写入的流。然后你可以放入模拟流或其他任何东西。请查看Mark Seemann在测试控制台上的这篇文章:
http://blogs.msdn.com/b/ploeh/archive/2006/10/21/consoleunittesting.aspx
答案 2 :(得分:4)
昨晚我偶然绊倒了这个帖子:Using reflection to override virtual method tables in C#。
@paulo提出答案:LinFu作者:Philip Laureano。
Philip Laureano's Development Blog: Intercepting Console.WriteLine上的用法示例将指导您完成如何拦截对Console.WriteLine方法的调用,以及(在本例中)执行一些其他操作的示例。 .AOP for .NET ... 非常吵,恕我直言!
LinFu可能只是故障单,因为它没有被拦截的东西存在,所以你可以“拦截和修改”呼叫对第三方供应商的程序集的行为“ em>你的上下文“,但没有任何可能影响那个上下文之外的截获类的ACTUAL行为 ......所以LinFu听起来像是一个开始实现”的好地方“控制台应用程序的通用测试框架“。
您甚至可以利用现有的单元测试框架之一。我正在寻找一个开源框架。 NUnit浮现在脑海中。双关语。
无论如何,祝你好运,这是一个有趣的项目。请告诉我们,K?
干杯。基思。
答案 3 :(得分:2)
我建议使用moles。
主要是因为我更喜欢让你的设计来确定你的接口和类,而不是你的测试。
答案 4 :(得分:0)
如果仅使用一个线程,则此代码将起作用:
[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();
}
}