Появилась необходимость выполнить большой рефакторинг в модуле документа. Правки в основном касались обработчика проведения, и т.к. их было очень много — я задался вопросом «как же все это проверить?»…
У меня была клиентская база, в которой было довольно много документов этого вида — ~60000. Если предположить, что эти документы охватывают все возможные ветвления алгоритма, то достаточно их перепровести, и проанализировать все наборы движений — до проведения, с наборами движений после. Отсутствие разницы можно считать успехом теста. Чтобы продолжить рассказ, введем термин "состояние системы", это "А" — до изменений, и "Б" — после изменений.
Действия сверки, пошагово:
- Подготовка тестового набора данных. Допустим тестировать буду все документы за 2024 год. Сначала необходимо убедиться, что в состоянии А перепроведение документа не вызывает изменения наборов. Для этого все документы надо перепровести в состоянии А, и проверить нет ли разницы в наборах.
- Если разница в наборах есть — необходимо устранить причины ее появления. Иначе будет невозможно понять в ходе теста, что изменения были вызваны ошибкой в новом алгоритме. Я на такое в своем примере не попал, но таковую возможность нельзя исключать. Хотя аксиомно и считается что при неизменном окружении перепроведение документа не должно породить разные наборы движений — все возможно)
- Когда тестовый набор состояния А подготовлен, перевести систему в состояние Б (внести правки), и повторить проведение. Если обнаружена разница по наборам движений, разобраться в причинах, и, в случае необходимости, повторить тест
Самое главное — как проверять движения? Я реализовал такой алгоритм:
- Добавляется регистр сведений "ИсторияСравненийИзменений", который будет хранить в себе ссылку на объект сравнения, а также данные результата сравнения
- В начале обработчика "ПередЗаписью" вызывается метод "РегистрыСведений.ИсторияСравненийИзменений.ДобавитьДанныеСравнения", записывающий все наборы движений в коллекцию документа "ДополнительныеСвойства"
- В конце обработчика "ОбработкаПроведения" вызывается метод "РегистрыСведений.ИсторияСравненийИзменений.ЗаписатьРезультатСравнения", в ходе которого выполняется сверка наборов движений из п.2 с текущими сформированными движениями документа. Если для какого-то набора движений обнаружены различия, то создается запись в регистр из п.1. В измерение "Объект" помещается ссылка на документ, в ресурс "Данные" (типа "ХранилищеЗначений") записывается информация о сверке. Приведу описание метода:
// Добавление записи в регистр "ИсторияСравненийИзменений".
// Измерение "Итерация" для переданного объекта автоматически повышается на 1.
//
//Параметры:
// ОбъектСравнения - ДокументСсылка
// ДанныеСравнения - Структура
// *Ключ - Имя набора данных, по которому была выявлена разница в составе записей после проведения
// *Значение - Структура, хранящая таблицы результата сравнения наборов движений. Присутствуют три значения, по ключам:
// **ТаблицаДо - ТаблицаЗначений - выгрузка движений по набору данных до проведения
// **ТаблицаПосле - ТаблицаЗначений - выгрузка движений по набору данных после проведения
// **ТаблицаРазниц - ТаблицаЗначений - таблица, содержащая отличающиеся строки между ТаблицаДо и ТаблицаПосле
//
Если после перепроведения документов системы в состоянии Б в этом регистре не оказалось записей — значит все нормально) В приложенном в публикации cf находится этот самый регистр:
Чтобы ускорить тест, я использовал материалы своей статьи Выполнение произвольного кода в фоновых заданиях — проводил в 10-ти потоках, по 6000 документов в каждом. В случае, если в регистре "ИсторияСравненийИзменений" оказались записи — их удобно анализировать с помощью исследователя объектов инструментов разработчика.
p.s.
Самое сложное здесь — это получение таблицы разниц, между наборами движений "До" и "После". Когда-то я болел идеей написать тестер: формируем некий произвольный набор данных (таблицу значений) по системе в состоянии А, прогоняем по базе алгоритм (переводим ее в состояние Б), формируем тот-же набор данных, и сравниваем эти два набора — разница между ними позволит судить о работоспособности алгоритма. Идея ушла в небытие, а набросок в виде алгоритма формирования текста запроса для сравнения двух произвольных типизированных таблиц значений остался. Его я здесь и использовал — возможно, кому-то пригодится.
А не проще ли xUnit начать использовать
Давно использую. 100% покрытия тестами не бывает.