«Hello World» - путь TDD? - PullRequest
       13

«Hello World» - путь TDD?

14 голосов
/ 27 апреля 2009

Ну, я думал об этом некоторое время, с тех пор, как я познакомился с TDD. Какой лучший способ создать приложение «Hello World»? который напечатал бы "Hello World" на консоли - используя Test Driven Development.

Как будут выглядеть мои тесты? а вокруг каких классов?

Запрос: Нет " wikipedia-like " ссылок на то, что такое TDD, я знаком с TDD. Просто интересно, как это можно решить.

Ответы [ 10 ]

21 голосов
/ 27 апреля 2009

Вам нужно спрятать Консоль за интерфейсом. (Это можно считать полезным в любом случае)

Написать тест

[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"));
}

Написать программу

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();
  }
}

Рефакторинг к чему-то более полезному; -)

5 голосов
/ 27 апреля 2009

Presenter-View? (модель не кажется строго необходимой)

Представление будет классом, который передает вывод на консоль (простые однострочные методы)

Presenter - это интерфейс, который вызывает view.ShowText («Hello World»), вы можете проверить это, предоставив представление заглушки.

Для производительности, я бы просто написал чертову программу:)

Достаточно одного теста (в псевдокоде):

IView view = Stub<IView>();
Expect( view.ShowText("Hello World") );

Presenter p = new Presenter( view );
p.Show();

Assert.IsTrue( view.MethodsCalled );
5 голосов
/ 27 апреля 2009

Ну ... я не видел TDD-версию Hello World. Но, чтобы увидеть такую ​​же простую проблему, к которой подходили с учетом TDD и управляемости, вы можете взглянуть на Enterprise FizzBuzz ( code ). По крайней мере, это позволит вам увидеть уровень чрезмерной инженерии, которого вы могли бы достичь в мире приветствия.

4 голосов
/ 27 апреля 2009

Псевдо-код:

  • Создайте макет чего-то, что принимает поток.
  • Вызвать helloworld на этот макет через своего рода внедрение зависимости (как аргумент конструктора).
  • Убедитесь, что строка "Hello World" была передана в ваш макет.

В рабочем коде вы используете подсказку вместо макета.

Правило большого пальца:

  • Определите критерии успеха в том, как компонент взаимодействует с другими вещами, а не только как он взаимодействует с вами. TDD фокусируется на внешнем поведении.
  • Настройка среды (макетов) для обработки цепочки событий.
  • Запустите его.
  • Проверьте.
3 голосов
/ 01 марта 2013

Предполагая, что вы знакомы с модульным тестированием, и, если вы понимаете, что это странный "красный процесс рефакторинга" (так как вы сказали, что знакомы с 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, чье «состояние» изменится, если консольная программа будет вызываться

Хорошо, я знаю, это звучит как долгий мыслительный процесс, но это окупается. Тдд заставляет вас думать, прежде чем кодировать, что лучше, чем кодировать, прежде чем думать

В конце дня вы можете найти что-то вроде следующего для вызова вашей программы:

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");
        }
    }

итоговый юнит-тест будет: -

 [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");



        }
3 голосов
/ 27 апреля 2009

Очень интересный вопрос. Я не большой пользователь 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");
}

Теперь у вас есть точка внедрения в метод, который позволяет вам использовать выбранную вами модель mocking, чтобы утверждать, что метод WriteLine вызывается с параметром «Hello World».

Проблемы, которые я оставил нерешенными (и я был бы заинтересован во вводе):

  1. Как протестировать класс ConsoleWriter, я думаю, вам все еще нужна какая-то инфраструктура тестирования пользовательского интерфейса для достижения этой цели, и если у вас это было, то вся проблема в споре в любом случае ...

  2. Проверка основного метода.

  3. Почему я чувствую, что чего-то достиг, изменив одну строку непроверенного кода на семь строк кода, только одна из которых фактически протестирована (хотя я предполагаю, что охват увеличился )

2 голосов
/ 27 апреля 2009

Я действительно должен возразить против вопроса! Все методологии имеют свое место, и TDD хорош во многих местах. Но пользовательские интерфейсы - это первое, что я действительно отхожу от TDD. Это, по моему скромному мнению, является одним из лучших обоснований шаблона проектирования MVC: протестируйте свои модели и контроллер программно; визуально осмотреть свой взгляд. То, о чем вы говорите, - это жесткое кодирование данных «Hello World» и тестирование их попадания на консоль. Чтобы выполнить этот тест на том же исходном языке, вам, скорее всего, потребуется заглушить консольный объект, , который является единственным объектом, который вообще что-либо делает .

Кроме того, вы можете написать свой тест в bash:

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

Немного сложно добавить в набор тестов JUnit, но что-то подсказывает мне, что это никогда не было планом ...

2 голосов
/ 27 апреля 2009

В java вы можете захватывать («перенаправлять») поток System.out и читать его содержимое. Я уверен, что то же самое можно сделать в C #. Это всего лишь несколько строк кода в Java, так что я уверен, что в C #

это не будет намного больше
1 голос
/ 07 июля 2010

Я согласен с Дэвидом Бергером; отделить интерфейс и протестировать модель. Кажется, что «модель» в этом случае является простым классом, который возвращает «Привет, мир!». Тест будет выглядеть так (на Java):

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

Я создал описание решения Hello World TDD в стиле http://ziroby.wordpress.com/2010/04/18/tdd_hello_world/.

0 голосов
/ 27 апреля 2009

Я думаю, что-то вроде этого:

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);
    }
}
...