“Hello World” – TDD方式?

自从我被介绍到TDD以来,我一直在思考这个问题。 哪个是构建“Hello World”应用程序的最佳方法? 这将在控制台上打印“Hello World” – 使用测试驱动开发。

我的测试会是什么样子? 和什么课程?

请求:没有“ 维基百科 ”链接到TDD是什么,我熟悉TDD。 只是好奇如何解决这个问题。

您需要在界面后面隐藏控制台。 (无论如何,这可能被认为是有用的)

写一个测试

[TestMethod] public void HelloWorld_WritesHelloWorldToConsole() { // Arrange IConsole consoleMock = MockRepository.CreateMock(); // primitive injection of the console Program.Console = consoleMock; // Act Program.HelloWorld(); // Assert consoleMock.AssertWasCalled(x => x.WriteLine("Hello World")); } 

写程序

 public static class Program { public static IConsole Console { get; set; } // method that does the "logic" public static void HelloWorld() { Console.WriteLine("Hello World"); } // setup real environment public static void Main() { Console = new RealConsoleImplementation(); HelloWorld(); } } 

重构更有用的东西;-)

演讲者视图? (模型似乎没有必要)

View将是一个将输出传递给控制台的类(简单的单行方法)

Presenter是调用view.ShowText(“Hello World”)的接口,您可以通过提供存根视图来测试它。

为了提高工作效率,我只想写该死的程序:)

单个测试应该足够(在伪代码中):

 IView view = Stub(); Expect( view.ShowText("Hello World") ); Presenter p = new Presenter( view ); p.Show(); Assert.IsTrue( view.MethodsCalled ); 

嗯……我没见过你好世界的TDD版本。 但是,要看到一个类似于TDD和可管理性的简单问题,您可以查看Enterprise FizzBu​​zz ( 代码 )。 至少这将使您能够看到在hello世界中可能实现的过度工程化水平。

伪代码:

  • 创建一个接受流的东西的模拟。
  • 通过某种dependency injection(如构造函数参数)将helloworld调用到此模拟上。
  • validation“Hello World”字符串是否已流入您的模拟。

在生产代码中,您使用提示而不是模拟。

经验法则:

  • 定义组件如何与其他内容交互的成功标准,而不仅仅是它与您的交互方式。 TDD专注于外部行为。
  • 设置环境(模拟)来处理事件链。
  • 运行。
  • 校验。

一个非常有趣的问题。 我不是一个庞大的TDD用户,但我会抛出一些想法。

我假设您要测试的应用程序是这样的:

 public static void Main() { Console.WriteLine("Hello World"); } 

现在,由于我无法想到任何直接测试这种方法的好方法,我会将写入任务分解为一个接口。

 public interface IOutputWriter { void WriteLine(string line); } public class ConsoleWriter : IOutputWriter { public void WriteLine(string line) { Console.WriteLine(line); } } 

并像这样打破应用程序

 public static void Main() { IOutputWriter consoleOut = new ConsoleWriter(); WriteHelloWorldToOutput(consoleOut); } public static void WriteHelloWorldToOutput(IOutputWriter output) { output.WriteLine("Hello World"); } 

现在您有了一个方法注入点,允许您使用您选择的模拟框架断言使用“Hello World”参数调用WriteLine方法。

我没有解决的问题(我对输入感兴趣):

  1. 如何测试ConsoleWriter类,我猜你还需要一些UI测试框架才能实现这个目标,如果你有这个,那么整个问题无论如何都是如此……

  2. 测试主要方法。

  3. 为什么我觉得我已经通过将一行未经测试的代码更改为七行代码来实现某些function,其中只有一行经过实际测试(尽管我认为覆盖范围已经上升)

假设您了解unit testing,并且假设您了解tdd“红绿重构过程”(因为您说您熟悉TDD),我会快速解释典型的tdd思维过程。

如果你想到一个特定的问题单元,那么你的TDD生活将会变得更容易,并且在依赖性方面应该考虑所有其他连接的东西。 这是一个样本

场景: – 我希望我的程序在控制台上显示hello world。

思想过程: –

“我认为我的程序将开始运行,然后调用控制台程序将我的消息传递给它,然后我希望我的控制台程序在屏幕上显示它”

“所以我需要测试一下,当我运行我的程序时,它应该调用控制台程序”

“现在有什么依赖?嗯我知道控制台程序就是其中之一。我不需要担心控制台如何将消息传递到屏幕上(调用io设备,打印等等)我只是需要知道我的程序成功调用了控制台程序。我需要相信控制台程序可以工作,如果没有,那么此刻我不负责测试并确保它有效。我想要测试的责任是我的程序在启动时调用控制台程序。“

“但我甚至不知道究竟要调用哪个控制台程序。我知道System.console.Writeline(具体实现)但是由于需求的变化,这可能会在未来发生变化,所以我该怎么办?”

“好吧,我将依赖于接口(或抽象)而不是具体实现,然后我可以创建一个虚拟控制台,实现我可以测试的接口”

  public interface Iconsole { void WriteToConsole(string msg); } public class FakeConsole : Iconsole { public bool IsCalled = false; public void WriteToConsole(string msg) { IsCalled = true; } } 

如果调用控制台程序,我已经把IsCalled成员的“状态”改变了

好吧,我知道这听起来像是一个漫长的思考过程,但确实有回报。 Tdd强迫你在编码之前思考,然后在思考之前编码

在一天结束时,您可能会提出类似以下方式来调用您的程序:

 var console = new FakeConsole(); console.IsCalled = false; my_program program = new my_program(console); program.greet(); 

我将控制台传递给my_program,以便my_program将使用控制台将我们的消息写入屏幕。

我的my_program可能如下所示:

 public class my_program { Iconsole _consol; public my_program(Iconsole consol) { if (consol != null) _consol = consol; } public void greet() { _consol.WriteToConsole("Hello world"); } } 

最后的unit testing将是: –

  [TestMethod] public void myProgramShouldDisplayHelloWorldToTheConsole() { //arrange var console = new FakeConsole(); console.IsCalled = false; my_program program = new my_program(console); //act program.greet(); //assert Assert.AreEqual(true, console.IsCalled, " console was not called to display the greeting"); } 

在java中,您可以捕获(“重定向”)System.out流并读取其内容。 我确信在C#中也可以这样做。 它只是Java中的几行代码,所以我相信它在C#中不会多得多

我真的不得不反对这个问题! 所有方法都有自己的位置,TDD在很多地方都很好。 但是用户界面是我真正退出TDD的第一个地方。 在我看来,这是MVC设计模式的最佳理由之一:以编程方式测试模型和控制器; 目视检查您的视图。 您所谈论的是对“Hello World”数据进行硬编码并测试它是否已进入控制台。 要使用相同的源语言进行此测试,您几乎必须虚拟控制台对象, 这是唯一可以执行任何操作的对象

或者,您可以在bash中编写测试脚本:

 echo `java HelloWorldProgram`|grep -c "^Hello World$" 

有点难以添加到JUnit测试套件,但有些东西告诉我,这绝不是计划….

我同意大卫伯杰的观点; 分离界面,并测试模型。 在这种情况下,似乎“模型”是一个返回“Hello,world!”的简单类。 测试看起来像这样(在Java中):

  Greeter greeter = new Greeter(); assertEquals("Hello World!", greeter.greet()); 

我在http://ziroby.wordpress.com/2010/04/18/tdd_hello_world/上创建了解决Hello World TDD风格的文章。

我猜是这样的:

 using NUnit.Framework; using System.Diagnostics; [TestFixture] public class MyTestClass { [Test] public void SayHello() { string greet = "Hello World!"; Debug.WriteLine(greet); Assert.AreEqual("Hello World!", greet); } }