Подтвердить что ты не робот

"Привет мир" - путь TDD?

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

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

Запрос: Нет ссылок, связанных с википедией, с тем, что такое TDD, я знаком с TDD. Просто любопытно, как это можно решить.

4b9b3361

Ответ 1

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

Записать тест

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

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

Ответ 2

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

Ответ 3

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

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

Ответ 4

Псевдо-код:

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

В производственном коде вы используете приглашение вместо макета.

Общее правило:

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

Ответ 5

Предполагая, что вы знаете модульное тестирование, и, учитывая, что вы понимаете "красный зеленый процесс рефакторинга" (поскольку вы сказали, что знакомы с TDD), я быстро объясню типичный процесс мышления tdd.

Ваша жизнь в TDD будет намного легче, если вы подумаете об определенной единице проблемы, и все другие связанные вещи должны рассматриваться в терминах зависимостей. здесь приведен пример

сценарий: - Я хочу, чтобы моя программа отображала мир приветствия на консоли.

Процесс мышления tdd: -

"Я думаю, что моя программа запустится, а затем вызовите консольную программу, передающую мое сообщение, а затем я ожидаю, что моя консольная программа отобразит ее на экране"

", поэтому мне нужно проверить, что, когда я запускаю свою программу, он должен вызывать консольную программу"

"теперь, каковы зависимости: hmm Я знаю, что консольная программа - одна из них. Мне не нужно беспокоиться о том, как консоль получит сообщение на экран (вызов устройства 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, чье "состояние" изменится, если вызывается когда-либо консольная программа

OK Я знаю, что это звучит как долгий процесс размышлений, но он окупается. 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 test будет: -

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



        }

Ответ 6

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

Ответ 7

Очень интересный вопрос. Я не являюсь огромным пользователем 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 для достижения этой цели, и если у вас что то вся проблема в тоо так или иначе...

  • Тестирование основного метода.

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

Ответ 8

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

В качестве альтернативы вы можете script выполнить тест в bash:

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

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

Ответ 9

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

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

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

Ответ 10

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

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