BDD и внешний подход, как начать с тестирования - PullRequest
1 голос
/ 28 октября 2011

Все,

Я пытаюсь понять все внешние данные в области TDD и BDD и хотел бы, чтобы вы помогли мне получить их.

Допустим, мне нужно реализовать ConfigФункциональность параметров работает следующим образом:

  • есть параметры в файле и в базе данных
  • обе группы должны быть объединены в один набор параметров
  • параметры из базы данных должны переопределятьте из файлов

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

С какого теста мне следует начать?Просто у меня есть что-то вроде следующего:

class ConfigurationAssemblerTest {

    @Test
    public void itShouldResultWithEmptyConfigurationWhenBothSourcesAreEmpty() {
        ConfigurationAssembler assembler = new ConfigurationAssembler();            
        // what to put here ?
        Configuration config = assembler.getConfiguration();            
        assertTrue(config.isEmpty());
    }

}

Я пока не знаю, с какими зависимостями я закончу.Я не знаю, как я все это напишу, и так далее.Что я должен поставить в этот тест, чтобы сделать его действительным?Должен ли я что-то издеваться?Если да, то как определить эти зависимости?

Если бы вы могли показать мне путь к этому, напишите какой-нибудь план, несколько тестов скелетов, что делать и в каком порядке это было бы супер-круто.Я знаю, что это много написано, так что, может быть, вы можете указать мне на любые ресурсы?Все ресурсы о внешнем подходе, которые я нашел, были о простых случаях без зависимостей и т. Д.

И два вопроса о насмешливом подходе.

  • если насмешка связана с взаимодействиями и их проверкой, означает ли это, что в таких тестах не должно быть утверждений о состоянии (только ложные проверки)?
  • , если мы заменим то, что не 'пока не существует с mock только для теста, мы заменим его позже на реальную версию?

Заранее спасибо.

1 Ответ

1 голос
/ 30 октября 2011

Хорошо, это действительно много вещей. Начнем с конца:

  • Насмешка не только о «взаимодействиях и их проверке», это всего лишь половина истории. Фактически, вы используете его двумя разными способами:

    1. Проверка, был ли сделан определенный вызов, и в конечном итоге также проверка аргументов вызова (это часть «взаимодействия и проверки»).

    2. Использование mocks для замены зависимостей тестируемого класса (CUT), в конечном итоге настройка возвращаемых значений для объектов mock по мере необходимости. Здесь вы используете фиктивные объекты, чтобы изолировать CUT от остальной части системы (чтобы вы могли обрабатывать CUT как изолированный «блок», который выполняется в песочнице).

Первую форму я бы назвал динамическим или «основанным на взаимодействии» модульным тестированием, в нем используются методы проверки вызова структур Mocking. Второе - более традиционное, «статическое» модульное тестирование, которое подтверждает факт.

  • У вас никогда не должно быть необходимости «заменить то, что еще не существует» (кроме того факта, что это - логически видно - совершенно невозможно). Если вы чувствуете, что вам нужно это сделать, то это явный признак того, что вы пытаетесь сделать второй шаг перед первым.

  • Относительно вашего представления о «внешнем подходе»: Честно говоря, я никогда не слышал об этом раньше, так что это, кажется, не очень выдающееся понятие - и, очевидно, не очень полезное потому что это, кажется, запутывает вещи больше, чем проясняет их (по крайней мере, на данный момент).

Теперь на ваш первый вопрос: ( С какого теста мне начинать? ):

  1. Перво-наперво - вам нужен какой-то механизм для чтения значений конфигурации из файла и базы данных, и эта функциональность должна быть заключена в отдельные вспомогательные классы (помимо прочего, вам нужен чистый Разделение задач для эффективного выполнения TDD - это обычно совершенно недооценивается при введении TDD / BDD). Я бы предложил интерфейс (например, IConfigurationReader), который имеет две реализации (одну для файловых ресурсов и одну для базы данных, например, FileConfigurationReader и DatabaseConfigurationReader). В TDD (не обязательно с подходом BDD) у вас также будут соответствующие тестовые приборы. Эти приборы будут охватывать контрольные примеры, такие как ' Что произойдет, если базовое хранилище данных не содержит / недопустимых / допустимых / других специальных значений? '. Это то, с чего я бы посоветовал вам начать.

  2. Только тогда - при работающем механизме чтения и наличии у вашего класса ConfigurationAssembler необходимых зависимостей - вы начнете писать тесты для / реализации класса ConfigurationAssembler. Тогда ваш тест может выглядеть так (потому что я парень на C # / .NET, я не знаю подходящих инструментов Java. Поэтому я использую здесь псевдокод):

    Класс ConfigurationAssemblerTest {

    @Test
    public void itShouldResultWithEmptyConfigurationWhenBothSourcesAreEmpty() {
    
        IConfigurationReader fileConfigMock = new [Mock of FileConfigurationReader];
        fileConfigMock.[WhenAskedForConfigValues].[ReturnEmpty];
    
        IConfigurationReader dbConfigMock = new [Mock of DatabaseConfigurationReader];
        dbConfigMock.[WhenAskedForConfigValues].[ReturnEmpty];
    
        ConfigurationAssembler assembler = new ConfigurationAssembler(fileConfigMock, dbConfigMock);            
    
        Configuration config = assembler.getConfiguration();            
    
        assertTrue(config.isEmpty());
    }
    

    }

Здесь важны две вещи:

  • Два объекта считывания вводятся в ConfigurationAssembler извне через его конструктор - этот метод называется Внедрение зависимости . Это очень полезный и важный архитектурный принцип, который обычно приводит к лучшей и более чистой архитектуре (и очень помогает в модульном тестировании, особенно при использовании фиктивных объектов).

  • Тест теперь точно подтверждает, что он заявляет: ConfigurationAssembler возвращает («собирает») пустую конфигурацию, когда лежащие в их основе механизмы чтения возвращают пустой набор результатов. И поскольку мы используем фиктивные объекты для предоставления значений конфигурации, тест выполняется в полной изоляции. Мы можем быть уверены, что мы тестируем только правильное функционирование класса ConfigurationAssembler (а именно, его обработку пустых значений) и ничего больше.

О, и, возможно, вам будет легче начать с TDD, а не с BDD, поскольку BDD является лишь подмножеством TDD и основывается на понятиях TDD.Таким образом, вы можете эффективно выполнять (и понимать) BDD только тогда, когда знаете TDD.

HTH!

...