Малюсенький мозг, такой как у меня, не сможет хорошо поработать над решением всех этих проблем, если они будут решаться одновременно. Две проблемы из приведенного списка можно легко отделить от всех остальных: «Что считать правильным результатом?» и «Как можно проверить правильность результата?»
Например, представьте, что нам надо реализовать обмен данными с другой системой через сокет. После завершения операции сокет должен быть закрыт, а в буфер должна быть прочитана строка abc:
testCompleteTransaction() {
…
assertTrue(reader.isClosed());
assertEquals("abc", reply.contents());
}
Откуда должен быть прочитан объект reply? Конечно же, из сокета:
testCompleteTransaction() {
…
Buffer reply = reader.contents();
assertTrue(reader.isClosed());
assertEquals("abc", reply.contents());
}
А откуда берется сокет? Мы создаем его, подключаясь к серверу:
testCompleteTransaction() {
…
Socket reader = Socket("localhost", defaultPort());
Buffer reply = reader.contents();
assertTrue(reader.isClosed());
assertEquals("abc", reply.contents());
}
Однако перед этим мы должны установить соединение с сервером:
testCompleteTransaction() {
Server writer = Server(defaultPort(), "abc");
Socket reader = Socket("localhost", defaultPort());
Buffer reply = reader.contents();
assertTrue(reader.isClosed());
assertEquals("abc", reply.contents());
}
Теперь мы можем изменить имена в соответствии с используемым контекстом, однако в данном случае мы малюсенькими шажками сформировали набросок теста, генерируя каждое решение в течение пары секунд. Мы начали с написания оператора assert.
Какие данные следует использовать для предварительных тестов? Используйте данные, которые делают тест простым для чтения и понимания. Помните, что вы пишете тесты для людей. Не разбрасывайте данные в изобилии по всему тесту только потому, что вам хочется добавить в тест как можно больше разнообразных данных. Если в разных местах теста используются разные данные, разница должна быть осмысленной. Если не существует концептуальной разницы между 1 и 2, используйте 1.
Вместе с тем, если ваша система должна поддерживать несколько разновидностей ввода, значит, все эти разновидности должны быть отражены в тестах. Однако не следует использовать в качестве входных данных список из десяти элементов, если при использовании списка из трех элементов будет получен точно такой же дизайн и реализация.
Старайтесь не использовать одну и ту же константу в нескольких местах для обозначения более чем одного понятия. Например, если вы намерены тестировать операцию plus(), вам наверняка захочется в качестве теста использовать операцию 2 + 2 – ведь это классический пример сложения. Возможно, вам захочется использовать другую операцию: 1 + 1 – ведь она самая простая из всех возможных. Однако не забывайте, что в данном случае речь идет о двух разных слагаемых, которые могут быть разными объектами. При использовании выражения 2 + 2 слагаемые оказываются одинаковыми, а значит, тест не является достаточно общим. Представьте, что в ходе дальнейшей разработки вы пришли к выводу, что результат выполнения операции plus() по тем или иным причинам должен зависеть от порядка слагаемых (сложно представить себе ситуацию, в которой результат сложения зависит от порядка слагаемых, однако может случиться, что операция plus() может перестать быть просто сложением, таким образом, общая идея должна быть вам понятной). Чтобы обеспечить более полноценное тестирование, попробуйте использовать 2 в качестве первого аргумента и 3 в качестве второго аргумента (в свое время тест 3 + 4 был классическим начальным тестом при запуске новой виртуальной машины Smalltalk).
Альтернативой шаблону «Тестовые данные» (Test Data) является шаблон «Реалистичные данные» (Realistic Data), в рамках которого для тестирования используются данные из реального мира. Реалистичные данные удобно применять в следующих ситуациях:
• вы занимаетесь тестированием системы реального времени, используя цепочки внешних событий, которые возникают в реальных условиях эксплуатации;
• вы сравниваете вывод текущей системы с выводом предыдущей системы (параллельное тестирование);
• вы выполняете рефакторинг кода, имитирующего некоторый реальный процесс, и ожидаете, что после рефакторинга результирующие данные будут в точности такими же, как до рефакторинга, в особенности если речь идет о точности операций с плавающей точкой.
Каким образом в тесте можно отразить назначение тех или иных данных? Добавьте в тест ожидаемый и реально полученный результат и попытайтесь сделать отношение между ними понятным. Вы пишете тесты не только для компьютера, но и для читателя. Через несколько дней, месяцев или лет кто-нибудь будет смотреть на ваш код и спрашивать себя: «Что имел в виду этот шутник, когда писал этот запутанный код?» Попробуйте оставить своему читателю как можно больше подсказок, имейте в виду, что этим разочарованным читателем можете оказаться вы сами.
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии