Перейти к основному содержимому

Тестовые данные

Тестовые данные, на мой взгляд, одна из самых сложных тем в тестировании решений на базе 1С:Предприятия.

Почти все алгоритмы системы опираются на данные базы, они их создают, обрабатывают, изменяют и используют в логике работы. Для корректного проведения одного документа может понадобиться множество записей справочников, настройки/остатки из регистров, значения констант и так далее. Все это вам придется создать в тесте, который проверит корректность проведения этого документа. И это будет проверка только одного кейса. Для проверки проведения в других условиях вам придется создать еще пачку данных и так далее.

Можно сократить объемы создаваемых данных используя мокито и отключая часть логики для каких-то кейсов, но все равно данных понадобится много.

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

Подходы к работе с данными​

  1. Ручное наполнение тестовой базы (мы предварительно создаем все что необходимо для тестов в базе, а потом используем её для прогона тестов)
  2. Использование файлов с данными (макеты - сгенерированные в нужном формате файлы с описанием тестовых данных, загружаемые при выполнении тестов)
  3. Программное создание нужных данных внутри теста

У каждого из вариантов есть свои плюсы и минусы и при грамотной компоновке можно достичь наилучшего результата.

  • Ручное наполнение базы не учитывает последующие доработки системы, нужна миграция на новые алгоритмы и структуру. А также в этом случае нам необходимо завязываться на конкретные записи в системе, и при их изменении тестом мы можем сломать другие тесты. Поэтому, предварительное наполнение базы должно быть минимальным.
  • В случае использования макетов данных возникают некоторые трудности с их доработкой и вариативностью, например, в новом тесте нужны данные из макета, но с некоторыми изменениями. В этом случае нам потребуется создавать новый макет или проверять, не сломают ли наши изменения другие тесты. Также при таком подходе сложно контролировать и искать какие макеты используются и кем.
  • Программное создание тестовых данных увеличивает время и сложность теста.

Если грамотно распределить тестовые данные на способы создания, можно добиться оптимального результата. Например, статичные данные создать вручную, сложные кейсы данных засунуть в макеты, а для программного создания реализовать методы-конструкторы, которые будем переиспользовать. Таким образом, сможем уйти от минусов того или иного подхода или минимизировать их вред.

Ниже хочу рассказать как мы работаем с данными.

Образ тестовой базы​

Для прогона тестов используется предварительно подготовленный образ базы, на котором гоняются тесты как в CI, так и на базах разработки.

Образ базы - это выгрузка (файл dt) или сама база (файл 1cd), на основании которого копированием или загрузкой создается база для прогона тестов.

Ручное наполнение тестовой базы​

Образ предварительно настраивается вручную (либо методами обновления/миграции), вводится минимально необходимая информация и базовые настройки.

В образе не должно быть документов, справочников и прочего, с чем обычно имеют дело пользователи, только минимальный набор неизменных данных.

Программное создание данных​

Все остальные данные тесты готовят для себя сами.

В большинстве случаев используется программное создание данных

  • Данные создаются кодом, используя механизмы движка
  • Используется генерация случайных значений, где это не противоречит требованиям
  • Тесты стараются прибрать за собой, используя транзакции или механизм удаления данных
  • Созданы отдельные модули-помощники реализующие типовые кейсы данных

Благодаря программной генерации данных вы получаете​

  • Старый добрый код 1С, который понятен и не требует изучения дополнительных материалов
  • Переиспользование и кастомизация алгоритмов генерации данных - общие модули, экспортные методы, параметры.
  • Возможность создавать новые уникальные данные
  • Можете использовать уже готовую логику тестируемого решения
Функция НовыйТовар() Экспорт
    // Логика генерации
КонецФункции

Функция НовыйПоставщик() Экспорт
    // Логика генерации
КонецФункции

Функция НовоеПоступлениеТовара(Склад, Знач Товар = Неопределено, Знач Поставщик = Неопределено) Экспорт
    
    Если Поставщик = Неопределено Тогда
        Поставщик = НовыйПоставщик();
    КонецЕсли;

    Если Товар = Неопределено тогда
        Товар = НовыйТовар();
    КонецЕсли;

    Возврат ЮТест.Данные().КонструкторОбъекта(Документы.ПоступлениеТоваров)
        .Установить("Склад", Склад)
        .Установить("Поставщик", Поставщик)
        .ФикцияОбязательныхПолей();
        .ТабличнаяЧасть("Товары")
            .ДобавитьСтроку()
            .Установить("Номенклатура", Товар)
            .Фикция("Количество")
            .Фикция("Цена")
        .Провести();
    
КонецФункции

Использование генерации случайных значений позволяет​

  • Сократить количество кода

  • Акцентировать внимание на "важных" значениях Например, в тесте ниже важно, чтобы товар и склад в документах совпадали, дата расхода должна быть больше прихода, количество расхода меньше прихода.

    Склад = ТестовыеДанные.НовыйСклад();
    Товар = ТестовыеДанные.НовыйТовар();
    
    ДатаПоступления = ЮТест.Данные().СлучайнаяДата();
    ДатаРасхода = ЮТест.Данные().СлучайнаяДатаПосле(ДатаПоступления);
    
    КоличествоРасход = ЮТест.Данные().СлучайноеПоложительноеЧисло(100);
    КоличествоПоступления = КоличествоРасход + ЮТест.Данные().СлучайноеПоложительноеЧисло(100);
    
    ТестовыеДанные.НовоеПоступлениеТовара(Склад, Товар, КоличествоПоступления, ДатаПоступления);
    ТестовыеДанные.НовыйРасходТовара(Склад, Товар, КоличествоРасход, ДатаРасхода);
    
    // Проверки
  • Вскрыть неожиданные проблемы, за счет случайности данных вы покрываете больше кейсов. Правда это имеет и негативный эффект - тесты могут "фонить", то падать, то успешно проходить, а также сложнее воспроизвести упавший тест.

Правильно организовав работу с тестовыми данными вы существенно облегчите процесс создания и поддержки тестов

  • Регламентируйте подход к именованию модулей и методов, это облегчит их поиск
  • Договоритесь как вы будете создавать общие модули, как разделяются по ним конструкторы, например:
    • Использовать один модуль на все методы-конструкторы, подходит для небольших решений.
    • Создаете модули по подсистемам (разрезы учета/функциональности) - для небольших и средних конфигураций.
    • Для каждого объекта/функциональности создается свой модуль с конструкторами - для больших и сложных проектов.
  • Выполняйте перекрестные ревью, делитесь знаниями в команде.