Насмешка TDD - указывает тестирование методом "белого ящика" поведения фиктивного объекта?

Я действительно добираюсь до TDD недавно, и после чтения книги Kent Beck по Разработке через тестирование, я все еще обошел много вопросов тестовый дизайн в моем уме.

Одной из проблем, которые я в настоящее время имею, является использование Фиктивных объектов. Возьмите ниже очень простого, которое генерирует отчет:

public string MakeFinancialReport()
{
    return sys1.GetData() + sys2.GetData() + sys3.GetData();
}

Отчет должен содержать заголовок, тело и нижний колонтитул. Так быстрый тест, чтобы видеть, существуют ли те заголовки в отчете:

public void TestReport()
{
    string report = MakeFinancialReport();
    Assert.IsTrue(report.Contains("[Title]") && report.Contains("[Body]") && report.Contains("[Footer]"));
 }

Для изоляции метода я предполагаю, что дразнил бы далеко sys1, sys2 и вызовы sys3. Теперь, если они - все насмешки, что я стал покинутым для тестирования? Кроме того, когда я действительно дразню их, почему должен я иметь сказать фиктивным объектам, что они собираются быть ожидаемыми быть названными однажды и возвратиться X и т.д. Это не должно только быть функциональное тестирование, и MakeFinancialReport может выполнить столько вызовов, сколько это хочет создать отчет?

Я запутываюсь с такой небольшой проблемой, я не уверен, что я пропускаю. Я рассматриваю Насмешку как убирание тестируемого кода, и для большинства простых методов, что оставляют протестировать, не полезно вообще.

9
задан Whymarrh 24 January 2015 в 03:10
поделиться

4 ответа

В нынешнем виде MakeFinancialReport почти ничего не делает, кроме взаимодействия с более интересными соавторами, и, вероятно, не стоит модульного тестирования.

Если бы я написал какие-либо модульные тесты для этого метода, я бы, вероятно, просто проверил, что метод делает то, что я ожидаю, когда его сотрудники возвращают null , в основном для документирования ожидаемого поведения (или для того, чтобы помочь мне решить об ожидаемом поведении, если я сделаю это заранее). В настоящее время метод просто не работает. Это может быть хорошо, но стоит подумать, хотите ли вы рассматривать нули как пустые строки - а модульные тесты доказывают, что любое поведение, которое вы выберете, является преднамеренным.

«Требуется ли проверка поведения фиктивного объекта с помощью белого ящика?» Абсолютно верно - если у вашего класса есть зависимость, которую вы издеваетесь, вы привязываете свой тест к этой зависимости. Но тестирование методом белого ящика имеет свои преимущества. Не все взаимодействия соавтора столь же тривиальны, как в вашем примере.

3
ответ дан 4 December 2019 в 21:49
поделиться

Вы должны использовать только имитацию объекты, когда они полезны. Если MakeFinancialReport , sys1 , sys2 и sys3 все содержат сложную логику, то вам нужно протестировать каждый из них. независимо. Предоставляя фиктивные версии трех объектов sysX в MakeFinancialReport , вы устраняете их сложность и просто тестируете MakeFinancialReport .

Мок-объекты особенно полезны, когда вы хотите протестировать условия ошибок и обработку исключений, потому что может быть сложно вызвать исключение из реального объекта.

Когда вы говорите об отсутствии необходимости устанавливать явные ожидания и возвращаемые значения, это связано с концепцией, называемой заглушками. Вы можете найти полезным " Mocks Aren't Stubs " Мартина Фаулера.

Книга Кента Бека - отличное введение, но если вы ищете более подробную информацию, я настоятельно рекомендую книгу xUnit Patterns . Например, в нем есть раздел о имитационных объектах , а также более общая категория тестовых двойников .

2
ответ дан 4 December 2019 в 21:49
поделиться

Я думаю, что одна из проблем заключается в том, что ваш тест смешивает обязанности sys1, sys2 и sys3 с обязанностями метода TestReport. Мне кажется, что вам следует разделить ваши тесты на 2 части:

1) MakeFinancialReport() возвращает конкатенацию sys1, sys2, sys3. Там вы можете заглушить sys1, и т.д..., чем-то вроде

var sys1 =MockRepository.GenerateStub<ISys>();
sys1.Expect(s=>s.GetData()).Return("Part 1");
// etc... for sys2, sys3 var
reportMaker = new ReportMaker(sys1,sys2, sys3); 
Assert.AreEqual("Part 1" + "Part 2" + "Part 3", reportMaker.MakeFinancialReport();

Класс, которому принадлежит метод MakeFinancialReport(), не должен заботиться или знать, что делают классы sys. Они могут возвращать любой класс - MakeFinancialReport() просто конкатенирует, вот что вы должны протестировать (если сочтете нужным).

2) Проверьте метод GetData() из интерфейса, который реализуют sys1, sys2, sys3. Скорее всего, здесь вы проверите, при каких обстоятельствах вы ожидаете увидеть "Body", "Title" и т.д....
Заглушка здесь может быть излишней, но что это дает вам, так это дешевый инстанс потенциально тяжелой зависимости (3 экземпляра sys), и четкое разделение того, что делает sys, и того, что делает MakeFinancialReport.

В качестве отступления, это может быть из-за языка, который вы используете, но удивительно, что ваш тест не начинается с инстанцирования класса, которому принадлежит MakeFinancialReport().

0
ответ дан 4 December 2019 в 21:49
поделиться

Мартин, я думаю, вам следует использовать моки для sys1-3, но они должны быть достаточно простыми, чтобы возвращать строку из одного символа каждая.

Это означает, что ваш тест должен выглядеть так:

public void TestReport()
{
    // Setup mocks for sys1-3
    string report = MakeFinancialReport();
    Assert.IsTrue(report.equals("abc"));
}

Это показывает, что MakeFinancialReport имеет свойства, что он вызывает GetData() из sys1-3 и конкатенирует результаты в этом конкретном порядке.

4
ответ дан 4 December 2019 в 21:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: