2016-01-27 2 views
2

Я довольно новичок в Test Driven Development, и я только начал изучать принципы SOLID, поэтому я надеялся, что кто-то сможет мне помочь. У меня возникли некоторые концептуальные проблемы с пониманием принципа единой ответственности в контексте разработки модульных тестов и методов в парадигме TDD. Так, например, сказать, что я хочу, чтобы разработать метод, который удаляет элемент из database-, прежде чем мой код выглядел бы следующим ...Одиночный принцип ответственности, разработка, основанная на тестах, и функциональный дизайн

Я хотел бы начать с определения тестового случая:

"Delete_Item_ReturnsTrue": function() { 
    //Setup 
    var ItemToDelete = "NameOfSomeItem"; 
    //Action 
    var BooleanResult = Delete(ItemToDelete); 
    //Assert 
    if (BooleanResult === true) { 
     return true; 
    } else { 
     console.log("Test: Delete_Item_ReturnsTrue() - Failed."); 
     return false; 
    } 
} 

я бы запустить тест, чтобы убедиться, что это не удалось, то я бы разработать метод ...

function Delete(ItemToDelete) { 
    var Database = ConnectToDatabase(); 
    var Query = BuildQuery(ItemToDelete); 
    var QueryResult = Database.Query(Query); 
    if (QueryResult.error !== true) { 
    //if there's no error then... 
     return true; 
    } else { 
     return false; 
    } 
} 

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

function Delete(WhatToDelete, WhereToDeleteItFrom) { 
    WhereToDeleteItFrom.delete(WhatToDelete); 
} 

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

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

Я разрабатываю и реализую дополнительную функцию, которая проверяет базу данных для использования в моем модульном тесте?

Я просто не проверяю его, потому что он недействителен? Как именно это работает в TDD?

Пройти ли я в mock-хранилище, а затем вернуть его после его изменения? Разве это не просто эссенциально возвращает меня к квадрату?

Передаю ли я ссылку на макет хранилища, а затем просто проверяю репозиторий после завершения этого метода? Разве это не считается побочным эффектом?

ответ

2

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

Итак, давайте посмотрим на вашу функцию:

function Delete(ItemToDelete) { 
    var Database = ConnectToDatabase(); 
    var Query = BuildQuery(ItemToDelete); 
    var QueryResult = Database.Query(Query); 
    if (QueryResult.error !== true) { 
    //if there's no error then... 
     return true; 
    } else { 
     return false; 
    } 
} 
  • базы данных изменений: ConnectToDatabese() нуждается в изменении, но не эту функцию
  • Изменения в структуре БД: BuildQuery() должен быть изменен (возможно)
  • ...

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

Имя BuildQuery кажется неправильным, поскольку BuildQuery (myItem) возвращает запрос, который что-то удаляет.

Но у меня никогда не было бы такой сложной функции, которая была бы только одной тестовой.

Вам необходимо написать больше тестовых примеров. Для первого теста вы можете написать функцию вроде этого:

function Delete(ItemToDelete) { 
    return true 
} 

Следующая TestCase может быть «вызвать функцию buildDeleteQuery с идентификатором элемента». В этот момент вам нужно подумать о том, как вы называете свой db. Если у вас есть dbObject, который делает это, вы можете издеваться над этим объектом.

function Delete(ItemToDelete) { 
    buildDeleteQuery(ItemToDelete.id) 
    return true 
} 

В настоящее время все больше и больше случаев испытаний. Помните, что будут также тестовые примеры для buildDeleteQuery. Но для внешней функции вы могли бы mock buildDeleteQuery.

Теперь, чтобы ответить на некоторые ваши вопросы:

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

Но самое главное: продолжайте практиковать! Когда вы начинаете с TDD, требуется некоторое время. Хорошим и интересным ресурсом является: Uncle Bobs Bowling Kata Просто скачайте слайды с веб-сайта и посмотрите, как tdd делается шаг за шагом.

Смежные вопросы