C# &引用;“你好,世界”TDD方式?

C# &引用;“你好,世界”TDD方式?,c#,unit-testing,tdd,nunit,C#,Unit Testing,Tdd,Nunit,自从我被介绍给TDD以来,我一直在思考这个问题。 构建“Hello World”应用程序的最佳方法是什么?它将使用测试驱动开发在控制台上打印“Hello World” 我的测试是什么样的?什么课程 请求:没有指向TDD的“类似维基百科”链接,我对TDD很熟悉。只是好奇如何解决这个问题 我猜是这样的: using NUnit.Framework; using System.Diagnostics; [TestFixture] public class MyTestClass { [Tes

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

我的测试是什么样的?什么课程


请求:没有指向TDD的“类似维基百科”链接,我对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);
    }
}
public class my_program
    {

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

嗯……我还没看过TDD版的hello world。但是,要想看到一个类似于TDD和可管理性的简单问题,您可以看看()。至少这会让你看到你在hello world中可能达到的过度工程化程度。

演示者视图?(模型似乎并非绝对必要)

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

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

但是为了提高效率,我只需要编写这个该死的程序:)

一次测试就足够了(在伪代码中):

IView view=Stub();
Expect(view.ShowText(“helloworld”);
演示者p=新演示者(视图);
p、 Show();
Assert.IsTrue(view.methodscaled);
在java中,您可以捕获System.out流(“重定向”)并读取其内容。我相信C#也可以做到这一点。java中只有几行代码,所以我相信C#

伪代码中的代码不会太多:

  • 创建一个接受流的模拟对象
  • 通过某种依赖项注入(如构造函数参数)将helloworld调用到此模拟上
  • 验证“Hello World”字符串是否已流式传输到模拟中
在生产代码中,使用提示符而不是模拟

经验法则:

  • 在组件如何与其他东西交互方面定义您的成功标准,而不仅仅是它如何与您交互。TDD关注外部行为
  • 设置环境(mock)以处理事件链
  • 运行它
  • 核实

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

编写测试

[TestMethod]
public void HelloWorld_WritesHelloWorldToConsole()
{
  // Arrange
  IConsole consoleMock = MockRepository.CreateMock<IConsole>();

  // primitive injection of the console
  Program.Console = consoleMock;

  // Act
  Program.HelloWorld();

  // Assert
  consoleMock.AssertWasCalled(x => x.WriteLine("Hello World"));
}

重构到更有用的东西;-)

一个非常有趣的问题。我不是一个巨大的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");
}
现在,您有了一个方法的注入点,该注入点允许您使用所选的模拟框架断言WriteLine方法是使用“Hello World”参数调用的

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

  • 如何测试ConsoleWriter类,我想您仍然需要一些UI测试框架来实现这一点,如果您有这样的问题,那么整个问题仍然存在争议

  • 测试主要方法

  • 为什么我觉得通过将一行未经测试的代码更改为七行代码,我已经取得了一些成就,其中只有一行真正经过了测试(尽管我猜覆盖率已经提高了)


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

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

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

    添加到JUnit测试套件有点困难,但有些事情告诉我,这从来都不是计划……

    我同意David Berger的观点;分离接口,并测试模型。本例中的“model”似乎是一个返回“Hello,world!”的简单类。测试如下所示(在Java中):


    我已经写了一篇关于解决
    Hello World
    TDD风格的文章。

    假设你了解单元测试,并且理解TDD“红-绿重构过程”(因为你说你熟悉TDD),我会很快解释一个典型的TDD思维过程

    如果您考虑一个特定的问题单元,那么您的TDD生活将变得容易得多,并且所有其他相关的事情都应该根据依赖性来考虑。这是一个样本

    情景:- 我希望我的程序在控制台上显示hello world

    tdd思维过程:-

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

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

    “现在什么是依赖项?嗯,我知道控制台程序就是其中之一。我不需要担心控制台如何将消息发送到屏幕上(调用io设备、打印等)我只需要知道我的程序成功地调用了控制台程序。我需要相信控制台程序能够正常工作,如果不能正常工作,那么目前我不负责测试和确保它正常工作。我想测试的责任是,我的程序在启动时调用控制台程序。”

    “但我甚至不知道要调用什么控制台程序。我知道System.console.Writeline(具体实现),但这可能会在将来因更改而改变
    echo `java HelloWorldProgram`|grep -c "^Hello World$"
    
      Greeter greeter = new Greeter();
      assertEquals("Hello World!", greeter.greet());
    
      public interface Iconsole
        {
           void WriteToConsole(string msg);
        }
    
    
    
     public class FakeConsole : Iconsole
        {
            public bool IsCalled = false;
    
            public void WriteToConsole(string msg)
            {
                IsCalled = true;
            }
        }
    
    var console = new FakeConsole();
        console.IsCalled = false;
        my_program program = new my_program(console);
        program.greet();
    
    public class my_program
        {
    
            Iconsole _consol;
            public my_program(Iconsole consol)
            {
                if (consol != null)
                    _consol = consol;
            }
            public void greet()
            {
                _consol.WriteToConsole("Hello world");
            }
        }
    
     [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");
    
    
    
            }