В этом году мне посчастливилось посетить конференцию KCDC здесь, в прекрасном Канзас-Сити. Одна из сессий, которые я посетил, была посвящена поведенческому развитию . Я уже посещал несколько сессий BDD и наслаждался каждым из них, но был один заданный вопрос, который отличал этот от других. Узнав обо всех преимуществах использования BDD в своей практике и обратившись к такому удивительному открытию, что произойдет, если у вас не будет каких-либо рамок или участия руководства для поддержки вашей миссии?
Как показывают сеансы BDD, такие среды, как Cucumber и JBehave, дают гибкой команде возможность создавать сценарии тестирования в текстовом формате. Итак, как вы изложите это самостоятельно и какие принципы BDD вы можете реализовать на уровне личного развития?
Поскольку BDD является расширением тестовой разработки, достаточно ли просто использовать принципы и ключевые слова BDD вплоть до уровня модульного тестирования. Приведение BDD к этому уровню начинается с следования шаблону именования, который Дэн Норт рекомендует для имен методов модульного тестирования.
В какой-то момент мы все использовали генератор тестовых классов в Eclipse, чтобы сэкономить время. Он дает вам предварительно заполненный класс, который добавляет слово test перед всеми видимыми именами методов, но это экономит время или помогает в долгосрочной перспективе? Легко ли сказать, для чего тестирует testCalculateCost () ? В конечном итоге вы добавите больше тестов для этого конкретного метода. Как вы будете различать имена методов для каждого дополнительного теста?
Дэн Норт рекомендует использовать предложения, основанные на поведении, для описания теста. Тестовый метод testCalculateCost () станет testShouldFailForMissingBillingDate () . Дэн также рекомендует использовать слово «поведение» в пользу пресловутого ключевого слова «тест» при описании того, что тестировать дальше. Более естественным является определение поведения метода calcCost () и сравнение следующего поведения с существующим поведением для устранения пробелов. Следующим естественным поведением для проверки может быть поведение отсутствующей даты выполнения с помощью testShouldFailForMissingBillingDueDate () .
Наряду с использованием соглашений об именах, предложенных Дэном Нортом, сеанс продемонстрировал, как организовать класс поведенческих тестов для имитации сценария тестирования BDD. Как и в сценариях BDD, написанных для JBehave для анализа, заданные / когда / затем ключевые слова BDD используются для построения и организации того, что необходимо в тестовом классе. Эти ключевые слова BDD заменяют ключевые слова упорядочения / действия / утверждения, обычно используемые в простых модульных тестах.
Перевод тестового ключевого слова в BDD:
Ключевое слово модульного теста → Ключевое слово BDD
Упорядочить / собрать → Дано
Act → Когда
Assert → Тогда
Хотя разработчики, не входящие в Agile, могут использовать этот стиль написания поведенческих тестов, не начинать с пользовательской истории может добавить к кривой обучения. Проще перевести пользовательскую историю, которая имеет ту же структуру, что и завершенные персональные тесты BDD, чем список требований. Мы будем использовать очень простую пользовательскую историю вместе с парой тестовых сценариев BDD, чтобы показать, насколько похожи пользовательская история, контрольный пример BDD и личный тестовый класс BDD.
пример
Мы работаем над историей пользователя, чтобы добавить функциональность в игру Судоку, чтобы пользователь мог проверить, верны ли выбранные числа во время игры. Следуя практикам BDD, функциональность игры еще не реализована.
История: Проверьте доску.
Для проверки выбранных номеров
Как игрок игры
Я хочу, чтобы игра проверила мои выбранные номера.
Структура BDD будет принимать что-то вроде этого:
Сценарий 1:
Игрок, который хочет знать, если у них есть неправильные номера
Учитывая игрока, у которого есть игра в процессе
Когда на доске все правильные цифры
игрок проверяет доску
Затем доска должна быть возвращена с подтверждением правильности
Сценарий 2:
Игрок, который хочет знать, если у них есть неправильные номера
Учитывая игрока, у которого есть игра в процессе
и на доске все правильные цифры
Когда игрок выбирает неправильный номер
Затем доска должна быть возвращена с подтверждением как неправильная
и неправильный номер будет помечен как неправильный
Так как мы вернулись с конференции и в нашем мире без BDD, нам придется использовать наш собственный творческий процесс, чтобы заполнить кишки нашего личного тестового класса BDD. Сначала тестирование с поведенческим подходом и не создание тестов, основанных на именах методов тестового устройства, будет немного более трудным и трудоемким, пока этот способ мышления не будет изучен. Переход в мир TDD был нелегким, но, по крайней мере, это будет эволюционный шаг.
С этим мы можем приступить к созданию нашего нового личного тестового класса BDD для тестирования поведения метода verify с использованием JUnit 4.
Следуя рекомендациям Дэна Норта, мы можем использовать имя SudokuBoardServiceSolveBehavior в качестве нашего тестового класса.
1
2
3
|
public class SudokuBoardServiceVerifyBehavior { ... } |
Когда мы заполняем наш тестовый класс, используя персональный BDD, мы будем использовать структуру и ключевые слова
дано / когда / то похоже на то, что в сценариях 1 и 2. Хотя у нас не будет сценариев, они помогают концептуализировать структуру и организацию тестового класса.
Данное ключевое слово будет использоваться для методов генерации тестовых приборов. Название метода поможет определить тестовое устройство и объем приемочных испытаний. Данный метод будет аннотирован аннотацией @Before JUnit и будет в общих данных. В нашем сценарии мы хотим начать с доски, частично заполненной правильными числами.
01
02
03
04
05
06
07
08
09
10
|
public class SudokuBoardServiceVerifyBehavior { @Before public void givenCorrectBoardNumbers() throws Exception { //stub the board board = TestBoardFactory.createPartialBoardWithCorrectNumberes(); //setup the service service = new SudokuBoardService(); } } |
Затем методы when содержат исполняемые шаги для выполнения тестового устройства. В зависимости от количества тестируемых поведений, у вас может быть несколько методов для одного данного метода. Каждый из них может охватывать сценарий тестирования BDD. Методы when будут аннотированы с помощью @Test JUnit.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public class SudokuBoardServiceVerifyBehavior { …. @Test public void whenUserPicksCorrectNumber() { //pick correct number board.setNumber(POS_X,POS_Y,5); } @Test public void whenUserSelectsInCorrectNumber() { //pick incorrect number board.setNumber(POS_X,POS_Y,4); } } |
Теперь у нас есть поведение, выполняемое на тестовом приборе. Последний шаг — выяснить, что случилось. Реализовали ли мы требования, как ожидалось? Мы скоро узнаем с тогдашними методами. Чем сложнее система, тем больше у вас будет, так как будет больше утверждений о поведении. Для ясности и наглядности у вас будет одно утверждение на то время . Когда вы обнаружите, что модульный тест не пройден, вы сразу узнаете и поймете, почему тест не прошел. Имя метода будет описывать то, что мы утверждаем. Когда методы будут ответственны за прохождение контроля их соответствующих тогда результатов.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
public class SudokuBoardServiceVerifyBehavior { private SudokuBoard board = null; private SudokuBoardService service = null; private static int POS_X = 0; private static int POS_Y = 0; @Before public void givenCorrectBoardAndCorrectNumbers() throws Exception { //stub the board board = TestBoardFactory.createPartialBoard(); //setup the service service = new SudokuBoardService(); } @Test public void whenUserSelectsCorrectNumber() { //pick correct number board.setNumber(POS_X,POS_Y,5); thenTheBoardIsVerifiedAsCorrect(); } @Test public void whenUserSelectsInCorrectNumber() { //pick incorrect number board.setNumber(POS_X,POS_Y,4); thenTheBoardIsVerifiedAsInCorrect(); theTheIncorrectNumberIsFlaggedAsIncorrect(); } private void thenTheBoardIsVerifiedAsCorrect() { service.verify(board); assertTrue(board.isCorrect()); } private void thenTheBoardIsVerifiedAsInCorrect() { service.verify(board); assertFalse(board.isCorrect()); } private void thenTheIncorrectNumberIsFlaggedAsIncorrect() { assertTrue(board.getNumber(POS_X,POS_Y).isCorrect()); } } |
Так что же здесь произошло, чтобы вывести BDD на личный уровень?
Вы просто стали заменой фреймворка. Вы только что перевели набор бизнес-требований в модульные тесты. Единственное отличие состоит в том, что вы использовали аннотации JUnit вместо набора аннотаций из Cucumber или JBehave. Хотя эти поведенческие тесты никоим образом не сравниваются со стоимостью того, что обеспечивает полная инфраструктура BDD, мы смогли представить принципы и структуру BDD на личном уровне. Персональный BDD по-прежнему предоставляет преимущества использования принципов BDD, чтобы сосредоточиться на поведении, которое непосредственно влияет на результаты бизнеса. Персональный BDD поможет в написании модульных тестов, которые предоставляют разработчикам убедительные доказательства того, что поведенческие аспекты системы работают. Тестирование становится более информативным с улучшенными соглашениями об именах классов и методов.
Чтобы придерживаться принципов BDD, тесты по-прежнему хорошо автоматизированы. Как только все тесты пройдут, появится полностью реализованная бизнес-функция, защищенная функциональными тестами.