[БЕЗ_ЗВУКА] В
предыдущем видео мы рассмотрели принципы тестирования и отладки решений.
В этом видео давайте применим их на примере задачи «минимальная строка».
Напомню эту задачу.
Итак, нам в стандартном входе дано три строки, разделенные пробелами, мы знаем,
что эти строки состоят из строчных латинских букв, и нам нужно в стандартный
вывод вывести лексикографически минимальную из этих строк.
Вот такую задачу мы сейчас с вами будем решать.
При этом давайте переключаемся в Eclipse, у нас уже есть какое-то решение.
Давайте убедимся, что оно компилируется.
Вот, я запустил компиляцию, оно компилируется,
и мы видим, что ошибок у нас никаких не возникло.
Как мы говорили, что нам надо сделать перед тем,
как отправлять в тестирующую систему, надо убедиться,
что наше решение корректно работает на примерах, которые даны в условии.
Давайте снова откроем условие и посмотрим, что у нас есть три примера: это строчки
milk milkshake month, строчки c, a, b и строчки fire fog wood.
Давайте на этих примерах поверим, что наше решение действительно работает корректно.
Итак, я запускаю программу и ввожу первый пример,
milk milkshake month.
И я вижу, что программа выдала milk.
И это правильный ответ для этого теста.
Следующий пример берем.
Строчки c, a, b, запускаю.
Выдалась строчка a.
Она действительно является лексическографически минимальной
из этих трех.
Ну, и наконец последний пример, fire fog wood.
Выдалась строчка fire, из чего мы делаем вывод,
что наше решение корректно работает на примерах,
поэтому кажется, нам ничто не мешает отправить его в тестирующую систему,
потому что все у нас вроде нормально.
Переходим в Coursera и отправляем
решение.
Выбираем файл.
Он загружается и отправляем.
[БЕЗ_ЗВУКА] Теперь дождемся, чтобы Coursera протестировала наше решение.
Итак, тестирование завершилось, и мы видим,
что тестирующая система говорит «незачет».
Мы не смогли написать правильное решение.
Давайте посмотрим, что нам говорит анализатор.
Анализатор говорит, что наше решение упало на десятом тесте,
и оно выдало неправильный ответ.
При этом больше никакой информации мы не видим.
Что мы должны делать в этом случае?
Мы говорили, мы должны перейти к тестированию нашего решения.
Причем, как мы должны тестировать?
Мы это обсуждали.
Мы должны составить план.
Давайте подумаем, как, какие классы входных данных есть в этой задаче?
Нам дано три строчки.
Из них надо выбрать минимальную.
При этом, если мы посмотрим на наше решение, то устроено оно таким образом: мы
сначала проверяем, является ли первая строчка ответом, и выводим, если это так,
иначе проверяем, является ли вторая строчка ответом, и выводим ее,
ну и наконец, если третья строчка является ответом, то мы выводим ее.
Тогда какой план тестирования мы могли бы построить?
Мы можем сказать, что первым вариантом входных данных является случай,
когда все три строчки разные.
При этом мы можем сделать три теста, когда
все строчки разные, при этом минимальной является первая, вторая или третья.
И вот здесь я в комментариях буду писать тесты на каждый из этих случаев.
Итак, давайте скажем, что первый тест нас будет alpha, beta, gamma.
Это три строчки, при этом alpha минимальная, она первая.
Дальше мы говорим, у нас опять же три строчки разные,
но минимальной является вторая.
И наконец, все три строчки разные, но минимальной является третья.
Хорошо.
Какие еще у нас могут быть классы входных данных?
Ну, например, у нас могут быть две одинаковых строки.
Давайте также для этого случая напишем тесты.
При этом мы должны проверить, что, например, вот эти две строки они,
например, являются ответом, то есть они меньше третьей,
и третья строка она может быть опять же либо первой, либо второй, либо третьей.
И мы можем написать такой тест.
Значит, и у
нас остался alpha, beta.
Так вот еще три теста, когда у нас есть две одинаковые строчки,
и третья, которая от них отличается, стоит на трех разных местах.
Тут она стоит на втором, тут на первом, тут на третьем.
Ну и наконец еще один класс входных данных,
это когда у нас все три строки одинаковые.
Прекрасно.
У нас получился план тестирования.
Что мы делаем дальше?
Тестируем нашу программу на каждом из этих тестов.
Компилируем ее еще раз на всякий случай и поехали.
Берем первый тест, копируем, запускаем нашу программу,
вставляем его в консоль, выполняем программу, выдалась alpha.
Отлично.
На этом тесте наша программа работает.
Берем второй тест.
Запускаем.
И снова выдалась alpha, снова работает.
Берем третий тест, запускаем, alpha, отлично,
на блоке тестов, где все три строчки разные, наш код работает.
Переходим к тестам, где есть две одинаковые строчки.
Копируем, запускаем.
Вставляем тест.
Выполняем программу, и она ничего не выводит.
Вот это очень странно,
то есть у нас дано три строчки и хоть одну-то мы должны были найти.
Но наша программа, вот давайте я ее еще раз выполню,
вот я ставил test, я нажал enter, программа выполнилась и ничего не выдала.
Давайте разбираться, в чем дело, почему она на этом, казалось бы,
простом тесте, ничего не выводит.
А в чем дело?
А в том, что мы для каждой строчки первой, второй или третьей, выполняем проверки.
Мы вот здесь проверяем, является ли первая строчка ответом.
Если нет, мы проверяем, является ли вторая строчка ответом.
Если ни первая, ни вторая не являются ответами, мы проверяем еще и третью.
Хотя ну если ни первая, ни вторая не являются ответами, значит,
ответом является точно третья.
Так что вот эта проверка тут явно лишняя.
Она не нужна.
Давайте ее уберем.
Скомпилируем программу.
Запустим.
Снова вставим в наш тест,
на который наша программа падала, выполним его и видим, что мы исправили ошибку.
Наша программа стала работать на нем правильно.
Что мы делаем дальше?
Конечно, нам не стоит сломя голову сейчас брать это решение и
отправлять его в Coursera.
Потому что мы говорили, что решение нужно отправлять только тогда,
когда оно прошло все тесты из нашего плана.
Это важно, потому что когда вы исправляли ошибку, вы могли, во-первых,
допустить новую, а, во-вторых, вы могли просто исправить не все ошибки,
которые есть в вашем коде.
Поэтому, несмотря на то, что мы исправили одну ошибку,
мы продолжаем двигаться по нашему тестовому плану.
Мы берем следующий тест, beta, alpha, alpha, и продолжаем тестировать нашу
программу, и мы видим, что на этом тесте наша программа работает правильно.
Нам осталось два теста, берем предпоследний,
тестируем и видим, что на тесте alpha, alpha, beta наша программа вдруг
говорит beta, хотя alpha ну явно лексикографически меньше.
То есть мы, конечно, одну ошибку исправили, но, как выяснилось, не все.
Давайте снова посмотрим, что у нас происходит в коде.
На этом тесте мы должны вывести либо строчку a, либо строчку b.
Но как мы тестируем, что строчка а является ответом?
Мы строго ее сравниваем со второй строчкой, со строчкой b, и со строчкой c,
но в нашем тесте a — это alpha, и b — это alpha.
Строгое сравнение на меньше не срабатывает, оно оказывается ложным.
Поэтому мы переходим в следующий if.
И здесь происходит то же самое.
Мы вот здесь сравниваем строго две строчки alpha, и эта проверка тоже не срабатывает.
И мы выводим третью строчку, просто потому, что мы только что решили,
что ее не надо тестировать.
Это ошибка.
Как ее исправить?
Давайте выполнять нестрогие сравнения.
Потому что если у нас несколько строк являются минимальными,
нам достаточно вывести одну и давайте ее выводить.
Отлично.
Компилируем.
Запускаем нашу программу и снова выводим тот тест, на котором она упала.
Супер.
Она теперь работает правильно и выводит alpha.
И мы опять же не спешим отправлять наши решения на проверку,
потому что мы по ходу движения по нашему тестовому плану исправили две ошибки, а,
значит, мы должны повторить тестирование на всех тестах, которые у нас есть.
Поэтому мы просто продолжаем двигаться дальше.
Берем тест с тремя одинаковыми строчками.
Тестируем.
Отлично!
Наша программа вывела строчку gamma, так как никакую другую она вывести не могла.
И теперь мы возвращаемся в начало нашего тестового плана и точно так же тестируем
наше решение.
Отлично.
alpha, beta, gamma, alpha.
beta, alpha, gamma, тоже alpha,
beta, gamma, alpha, alpha.
Берем тест alpha, beta, alpha, на котором наша программа падала,
теперь она работает корректно.
Отлично!
Мы прошли по всему нашему тестовому плану и видим,
что наша программа корректно работает на всех наших тестах.
Давайте отправим наше решение в Coursera и проверим,
смогли ли мы исправить все ошибки, которые у нас были.
Открываем, обновляем файл.
[БЕЗ_ЗВУКА] Отправляем и ждем,
когда наше решение протестируется.
Готово.
Наше решение протестировалось, и мы видим, что оно принято.
Тестирующая система приняла наше решение.
Отлично, мы только что смогли исправить ошибки и сдать решение
задач в тестирующую систему.
Давайте подведем итоги.
Что мы узнали?
Если ваше решение не принимается тестирующей системой,
это не повод для паники.
Нужно просто его как следует протестировать.
При этом тестировать решение нужно в соответствии с планом.
Нужно выделить все возможные случаи входных данных и проверить,
что ваше решение корректно работает на них на всех.
Обязательно не забыть учесть крайние случаи.
Ну и наконец, решение стоит отправлять в тестирующую систему,
когда оно прошло все ваши тесты, потому что если у вас есть тест,
на котором ваше решение не работает, скорее всего, такой тест есть и у нас.