четверг, 5 апреля 2018 г.

Классы эквивалентности для строки, которая обозначает дату

Большинство примеров про классы эквивалентности приводятся для чисел. Самый заезжанный пример — тестирование калькулятор. Он используется в книгах и статьях, потому что простой и понятный.

Но потом доходит до дела и сразу ступор: а как применять классы эквивалентности где-то еще? Ладно, используем правило «ищи число»: если речь идет о поле с символами, берем длину поля (число) и тестируем на границы. Вроде все хорошо, логично и понятно.

Однако на своих студентах я заметила, что это правило стало серебряной пулей. Если это нечисловое поле — по границам тестируем ТОЛЬКО на длину. Точка. Просишь протестировать дату, получаешь примерно такой ответ:
  • Нормальная дата (17.03.2018)
  • Дата «в прошлом» или «в будущем» (смотря что подходит под ваше ПО)
  • Пустое поле
  • Нафигачили туда 100500 символов
  • Ввели «0»
За сим границы и проверены. И даже ноль проверен, чем тренер недоволен? А тренер недоволен тем, что по границам вместо ДАТЫ тестируется СТРОКА. Поэтому я предлагаю написать проверки именно для даты. И прежде, чем читать дальше, отложите книгу в сторону и попробуйте сами набросать эти проверки.  А потом сравните, все ли вы нашли?




Четкий формат дд.мм.гггг



Допустим, я могу ввести в профиле свою дату рождения и система сама посчитает, сколько мне лет. Формат даты известен заранее, на поле стоит маска, дату в другом формате я ввести не смогу.


Что будем тестировать?
  1. Своя дата рождения — основной позитивный тест.
  2. ...

Дальше думаем, а какие у нас тут классы эквивалентности вообще есть? Если по ТЗ есть какие-то ограничения или предположения, то проверяем их. Скажем, считается, что возраст участников должен быть больше 18 лет. Ага, у нас сразу есть классы:
  1. От 0 до 18
  2. От 18 до бесконечности
  3. Меньше 0

Пункт 2 при этом разбивается с помощью знаний о типах границ:
  • «примерно адекватный возраст» — 45 лет 
  • «подозрительный» — 200 (логично, что это какая-то подстава)
  • Поиск технологической границы — тысячи лет. С ограничением по формату максимально возможный

Разные классы: «много», которое реальное и не очень реальное число

Если никаких ограничений нет, все равно включаем логику — дата рождения не может быть отрицательной. Так что уже как минимум есть граница в TODAY (сегодняшнее число). Надо проверить, можно ли ввести меньше и больше.

По идее, календарик должен блокировать выбор дальше текущего числа. Логично, конечно, усложнить и не давать вводить возраст до 4 лет, но это дополнительные ограничения из серии «а зачем?». А вот «не вводить дальше, чем сегодня» — стандартная практика, вполне можно использовать.

Если ввели с клавиатуры, можно подсвечивать поле красным и выдавать ошибку «Дата рождения должна быть меньше текущей даты». Но даже если никаких ограничений нет, мы просто проверяем, как поведет себя система при вводе этой логической границы и попытке выйти за ее пределы.

Но как быть с другими границами? Которых нет в ТЗ...


Нижняя граница


Всегда тестируем ноль! Но у нас четкий формат даты... Разве это мешает? Что будет, если ввести:
  • 00.00.0000 → нули везде
  • 12.03.0000 → нули только в году
  • 12.00.1989 → нули только в месяце
  • 00.03.1989 → нули только в дате

Казалось бы, ничего сложно в этом нет. Мы тестируем уже знакомый ноль, просто запихиваем его в наш формат. Но практика показывает, что начинающие не делают такие тесты. Вот «вместо даты написать 0» — это мы можем. А написать «00.00.0000» — нет.

Конечно, это негативная проверка из серии «упадет / не упадет». Зачем нам четыре теста вместо одного? Потому что разработчик мог поставить защиту от дурака от даты «00.00.0000», а вот если нули только в одном компоненте — ой, все пропало.

Если говорить о нижней границе, то помимо нуля я рекомендую проверить:

  • 01.01.1900 — магическая дата, на которой все падает. 

С этой даты начинается отсчет времени в Excel. Она же пролезает и в приложения. Выставишь это магической число — и отчет разваливается, даже если есть защита от дурака на нули. Так что настоятельно рекомендую ее к проверке.

А еще некоторые системы сбрасывают в «01.01.1900» всякий треш, пришедший на входе. Ведь с точки зрения системы это вполне корректная дата, так что это бывает значением «по-умолчанию». По крайней мере, я видела такое поведение в системах, с которыми мы интегрировались на работе.

Нижние границы даты

И еще есть полезная для проверки дата:
  • 01.01.1970 — unix-овый ноль
На ней тоже вылезают косяки!


Верхняя граница


Вы, наверное, уже догадались, что если нижняя граница «00.00.0000», то верхняя будет «максимум девяток»:
  • 99.99.9999 → везде треш
  • 12.03.9999 → только в году
  • 12.99.1989 → только в месяце
  • 99.03.1989 → только в дате
Это такой поиск технологической границы на уровне даты, а не просто строки ввода. Правда, это ограничение именно на ввод.

А что, если мы тестируем фильтрацию по уже существующим датам, которые подготовили заранее? Запихать в базу 99.99.9999 вы не сможете: ни один формат SQL для даты физически не позволяет хранить такую дату. В MySQL, например, неверные форматы превращаются в '0000.00.00' , но это уже нижняя граница. Да и зачем нам тестировать базу? Мы тестируем приложение! Поэтому если мы говорим о том, что лежит в базе, то проверяем реально возможную максимальную дату:

  • 9999-12-31 → максимум в БД

Помимо технологии, вспоминаем о логике и проверяем какую-то нереальную дату типа 31 февраля. С годом тут «налажать» сложно, а вот с днем и месяцем — вполне!
  • 31.02.2010 — плохая дата
  • 12.15.2010 — плохой месяц
  • 35.15.2010 — оба плохие

Верхние границы даты



Просто строка с датой

Просто поле для ввода

Даже если у нас нет ограничения на формат, мы сначала смотрим на строку как на дату. Это очень важно — видеть в поле тот смысл, который заложил туда разработчик, а не просто абстрактную строку. Вы ведь не знаете заранее, как она обрабатывается. Может быть, никак, это правда строка. А может, над ней висят какие-то правила, ограничения, преобразования...

Поэтому наш план действий:
  1. Проверить дату по ТЗ (если там установлены границы)
  2. Проверить дату как дату формата дд.мм.гггг (типовой формат)
  3. Проверить другие форматы
  4. Проверить саму строку ввода

Только в таком порядке. А никак не «начнем с того, что это просто строка и введем туда 0».

Как тестировать дату конкретного формата, мы рассмотрели выше. Надеюсь, не надо пояснять, что маска на поле может быть любой, хоть дд.мм.гггг, хоть гггг/мм/дд, хоть какая-то другая. Это не мешает нам подставить туда все нули, все девятки или ввести магическое 01.01.1900.

Рассмотрим оставшиеся пункты.


Разные форматы даты


Система умеет работать только с российским форматом? Или с другими тоже? Проверяем основные:

Страна/язык
Формат даты
Пример даты
Россия, Германия
DD.MM.YYYY
26.01.1993
США
MM-DD-YYYY
01-26-1993
Международный английский
DD-MM-YYYY
26-01-1993
Великобритания, Италия
DD/MM/YYYY
26/01/1993
Венгрия, Канада, Польша
YYYY-MM-DD
1993-01-26


Или вот табличка распространенных форматов из википедии, тут еще больше извращений:


Формат              Пример             Страны

гггг.ММ.дд        2006.05.30          Венгрия
гггг-ММ-дд       2006-05-30         Польша, Швеция, Литва, Канада
гггг/ММ/дд       2006/05/30          Иран, Япония
гггг-М-д              2006-5-30          КНР
гггг/М/д              2006/5/30           Гонконг, Тайвань
гггг.дд.мм          2006.30.05          Казахстан (используется в документах на казахском языке)[8]
д.М.гггг               30.5.2006          Финляндия, Чехия
д-М-гггг              30-5-2006          Нидерланды
д/М/гггг              30/5/2006           Бразилия, Греция, Таиланд
дд.ММ.гггг        30.05.2006          Болгария, Германия, Норвегия, Румыния, Россия, Словения,
дд-ММ-гггг       30-05-2006         Дания, Португалия
дд/ММ/гггг       30/05/2006          Великобритания, Вьетнам, Израиль, Индонезия, Испания

М/д/гггг              5/30/2006           США

А что будет, если записать дату в формате экселя или базы данных?
  • 2009-06-15T13:45:30 — международный формат по ISO 8601
  • 14 марта 2018 г.
  • 14 марта
  • 08 Jul

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

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

  • MM-DD-YYYY
  • DD-MM-YYYY

Так что разработчик вполне мог навинтить логику из серии «если второе число больше 12 — значит, формат мм.дд.ггггг, а не дд.мм.гггг). А, может, он сразу ориентируется на такой формат. И если вы введете «01.01.2010», то будете думать, что система работает правильно. А бедный пользователь попробует указать 16.01.2010 и огребет ошибку «Введите корректную дату».

Плохой тест не найдет ошибку :)


Строка ввода


Ну и, наконец, мы дошли до проверки строки как строки. Закатываем рукава по локоть, гордо вводим «1 000 000 000» и получаем... Корректный результат? о_О

Не пугайтесь заранее, вполне возможно, что система умеет понимать UNIX-время . Так что с ее точки зрения вы просто ввели «9 сентября 2001 года, 01:46:40 UTC».

Но в любом случае для строки мы уже знаем, как искать нижнюю и верхнюю границы:
  • (пустая строка)
  • (только пробел)
  • 0
  • 999999999999999999999999999999999999... (100 млн девяток) 


См также:
Класс эквивалентности «Ноль-не ноль» — помогает при тестировании нижних границ
Как сгенерить большую строку, инструменты — а это, наоборот, для поиска верхней границы


Резюме


Всегда тестируйте конкретное поле, а не абстрактную строку!
И если речь идет о ДАТЕ, очень хочется, чтобы вместо стандартных тестов на границы:
  • (пустая строка)
  • 999999999999999999999999999999999999...

Вам в первую очередь приходили границы на даты:
  • 00.00.0000
  • 99.99.9999
  • 01.01.1900 (ноль в экселе, и вообще магическое число)
  • 01.01.1970 (unix-овый ноль)

Серебряную пулю вы всегда успеете проверить. Но начинать с нее не надо. И с «00.00.0000» не надо. Всегда сначала позитив, потом границы по ТЗ, а потом уже прочие извращения. И вот в извращениях мы сначала проверяем границы в формате даты, а потом уже все остальное.




PS — это выдержка из моей книги для начинающих тестировщиков, написана в помощь студентам моей школы для тестировщиков

10 комментариев:

  1. Просто оставлю тут: 1 Января 4712 до нашей эры

    ОтветитьУдалить
  2. 29.02.1900 - радуйтесь! Стандартная ошибка многих программистов. Прекрасно описана у Спольски.

    > Всегда сначала позитив, потом границы по ТЗ, а потом уже прочие
    извращения.
    Не-а... Есть разные стратегии. Подбирается под проект.
    Оль, все правильно пишешь.
    Но. Есть игры с "красными пиками".

    ОтветитьУдалить
  3. Ответы
    1. У меня пока тяжко с тем, чтобы выбраться куда-то. Но зато у нас можно проводить тренинги на 15 человек бесплатно, так что лучше ты заходи :)

      Удалить
  4. Здравствуйте, Ольга.
    Вы шикарно пишете и примеры замечательные, но раз уж речь зашла о датах, то не смогла пройти мимо,в дополнение:
    31.12.1999(максимально допустимые месяц и день)
    01.01.1999(минимально допустимые месяц и день)
    31.06.1999(вдруг во всех месяцах 31 день да и фильм шикарный) - кривая дата
    30.06.1999(скорее паранойя, но может быть такое, что все месяцы где не 31 один день -февраль)
    29.02(високосный год)
    29.02(не високосный год) - кривая дата
    Ну и хорошо бы посмотреть долгожителей, максимальный возраст жизни , что нашла 122 года ( зайдет весьма почтенный человек 120 лет, а ему сообщение "столько не живут!" так и до беды не далеко)

    ОтветитьУдалить
  5. Здравствуйте! Возник вопрос. А нужно ли нам тестировать граничные значения для дней каждого месяца?

    ОтветитьУдалить
  6. Спасибо, всё очень хорошо описано. Такое приятное и емкое резюме полного тестирования поля с датой.
    От себя - почти всегда забываю при тестировании подобных полей даты в unix-формате смотреть.

    PS
    >Конечно, здесь можно и нужно применять тест-анализ. Если у вас на входе просто
    >строка, а система из нее умеет распознавать только запись в формате дд.мм.ггггг
    возможно там одно "г" лишнее

    ОтветитьУдалить