|
Назад
Содержание
Далее
FuncTest. Как тестировать отчеты
Небольшая вводная.
Для начала.
Для начала - две новости, одна хорошая, вторая плохая. Сначала плохая.
Произвольный отчет протестировать не получится. Прежде чем
отчет можно будет тестировать - он должен быть соответствующим образом написан/поправлен.
Теперь хорошая новость. С версии 0.9.9 Фанктест научился сравнивать печатные
формы, а это значит, что любой отчет можно достаточно оперативно подготовить
для тестирвоания.
"Оригинальный" механизм тестирования отчетов описан на этой странице, а
новый (со сравнением печатных форм) - на следующей.
Основная идея.
Основная идея тестирования заключается в том, что мы сравниваем наше ожидание с
действительно полученным результатом. Основная проблема тестирования отчетов заключается
в том, что мы - люди, и наше ожидание от отчета является некоторой печатной формой.
Здесь нужно совершить некоторое насилие над собой и разделить логику формирования отчета на две части.
(Это разделение нужно сделать и у себя в голове, и в коде отчета:).
Первая часть будет формировать набор данных, составляющих суть отчета, вторая часть
будет выводить этот набор данных на экран/принтер. Следующий шаг: если от отчета ожидать не
печатную форму, а набор данных, то такое ожидание гораздо проще протестировать.
Мы умеем выражать наши ожидания в виде Таблицы Значений. Если отчет тоже сможет возвращать
Таблицу Значений мы сможем сравнить эти таблицы. Это и будет тестированием отчета. Более того, сложные отчеты
зачастую именно так и формируются: разноплановые данные собираются в Таблицу Значений, в ней
сортируются, фильтруются, группируются, и только потом выводятся на экран.
Пример.
С чего начнем.
Чтобы не стало слишком скучно от голословных утверждений - приведу маленький пример доработки отчета.
Пример действительно маленький, и кому-то может показаться, что тестировать его - только
время терять. Не будьте строгими - это просто пример. Отчет называется "Реестр Счетов".
Для всех проведенных счетов за указанный период времени по указанной фирме этот реестр
выводит дату, номер, название клиента и сумму счета. Модуль его процедуры Сформировать() такой:
Т=СоздатьОбъект("Таблица");
Т.ВывестиСекцию("Шапка");
Сч=СоздатьОбъект("Документ.Счет");
//ДатаС и ДатаПо - реквизиты на форме отчета
Сч.ВыбратьДокументы(ДатаС,ДатаПо);
Пока Сч.ПолучитьДокумент()=1 Цикл
Если Сч.Проведен()=0 Тогда
Продолжить;
КонецЕсли;
//ВыбФирма - реквизит на форме отчета
Если Сч.Фирма<>ВыбФирма Тогда
Продолжить;
КонецЕсли;
//Все необходимые вычисления происходят в печатной форме отчета
Т.ВывестиСекцию("Строка");
КонецЦикла;
Т.ВывестиСекцию("Подвал");
Т.Показать();
|
Результат отчета - в таблицу значений.
Для начала я создам Таблицу Значений, куда сложу данные отчета. В этом (простом) случае
эта таблица вполне может содержать одну колонку "Счет" типа "Документ.Счет". До всех нужных
реквизитов счета я доберусь уже на стадии вывода на печать. Теперь модуль такой
(изменения выделены жирным):
Отчет=СоздатьОбъект("ТаблицаЗначений");
Отчет.НоваяКолонка("Счет");
Т=СоздатьОбъект("Таблица");
Т.ВывестиСекцию("Шапка");
Сч=СоздатьОбъект("Документ.Счет");
Сч.ВыбратьДокументы(ДатаС,ДатаПо);
Пока Сч.ПолучитьДокумент()=1 Цикл
Если Сч.Проведен()=0 Тогда
Продолжить;
КонецЕсли;
Если Сч.Фирма<>ВыбФирма Тогда
Продолжить;
КонецЕсли;
Отчет.НоваяСтрока();
Отчет.Счет=Сч.ТекущийДокумент();
Т.ВывестиСекцию("Строка");
КонецЦикла;
Т.ВывестиСекцию("Подвал");
Т.Показать();
|
Данные для печати - из таблицы значений.
Теперь нужно переработать кусочек вывода на экран так, чтобы данные брались из Таблицы "Отчет".
Более того - эту часть кода я выделю в отдельную процедуру.
Процедура НапечататьОтчет(Отчет)
Т=СоздатьОбъект("Таблица");
Т.ВывестиСекцию("Шапка");
Отчет.ВыбратьСтроки();
Пока Отчет.ПолучитьСтроку()=1 Цикл
Т.ВывестиСекцию("Строка");
//В секции "Строка" нужно поменять обращения к переменной Сч на выражение Отчет.Счет
КонецЦикла;
Т.ВывестиСекцию("Подвал");
Т.Показать();
КонецПроцедуры()
Процедура Сформировать()
Отчет=СоздатьОбъект("ТаблицаЗначений");
Отчет.НоваяКолонка("Счет");
Сч=СоздатьОбъект("Документ.Счет");
Сч.ВыбратьДокументы(ДатаС,ДатаПо);
Пока Сч.ПолучитьДокумент()=1 Цикл
Если Сч.Проведен()=0 Тогда
Продолжить;
КонецЕсли;
Если Сч.Фирма<>ВыбФирма Тогда
Продолжить;
КонецЕсли;
Отчет.НоваяСтрока();
Отчет.Счет=Сч.ТекущийДокумент();
КонецЦикла;
//Закончилось формирование таблицы отчета - выведем ее на экран.
НапечататьОтчет(Отчет);
КонецПроцедуры
|
Простой рефакторинг.
Теперь мне нужно, чтобы Таблицу Значений "Отчет" я смог получить и из других процедур
своего отчета. Это просто - весь текст процедуры Сформировать() до комментария я выделяю
в функцию СформироватьОтчет(), которая формирует Таблицу и возвращает ее значение. Теперь
процедура Сформировать() состоит из одной строки:
Процедура Сформировать()
НапечататьОтчет(СформироватьОтчет());
КонецПроцедуры
|
Ключевой момент.
Теперь вкусное. Я хочу использовать свой отчет, как функцию. Во-первых, мне нужно передать
начальные параметры (значения реквизитов формы ДатаС, ДатаПо и ВыбФирма); и во-вторых, отчет
должен вернуть мне таблицу значений с данными отчета.
FuncTest понимает три варианта отчетов-функций.
- Первая техника превращения отчета в функцию
нагло позаимствована на сайте http://e1s.chat.ru.
На форме отчета размещается ТаблицаЗначений (я даю этой таблице имя "ПолученныйРезультат").
В процедуре ПриОткрытии() анализирую параметр. Я хочу, чтобы мне здесь дали Список Значений,
такой, чтобы у значения, где лежит, например, значение фирмы - представление было "ВыбФирма".
Вот текст процедуры:
Процедура ПриОткрытии()
Условия=Форма.Параметр;
Если ТипЗначенияСтр(Условия)="СписокЗначений" Тогда
ДатаС=Условия.Получить("ДатаС");
ДатаПо=Условия.Получить("ДатаПо");
ВыбФирма=Условия.Получить("ВыбФирма");
ЧтоДелать=Условия.Получить("ЧтоДелать");
Если ЧтоДелать="Тестировать" Тогда
Результат=СформироватьОтчет();
Результат.Выгрузить(ПолученныйРезультат);
КодОшибки = 0; // это тоже реквизит на форме
Форма.Закрыть();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
|
В качестве небольшого дополнения. FuncTest предполагает, что в отчете есть еще числовое поле
с идентификатором "КодОшибки", в котором 0, если все хорошо, и не 0, если случилась какая-то
исключительная ситуация (см. комментарий в модуле).
Я создал для себя параметр "ЧтоДелать" - в дальнейшем это позволит мне малой ценой расширить
возможности этого отчета. Я смогу его сформировать по переданным условиям, или просто открыть,
автоматически заполнив реквизиты, да мало ли что еще.
- Второй способ - намного проще первого, поскольку не требует размещения
на форме дополнительных реквизитов.
Процедура ПриОткрытии()
Условия=Форма.Параметр;
Если ТипЗначенияСтр(Условия)="СписокЗначений" Тогда
ДатаС=Условия.Получить("ДатаС");
ДатаПо=Условия.Получить("ДатаПо");
ВыбФирма=Условия.Получить("ВыбФирма");
ЧтоДелать=Условия.Получить("ЧтоДелать");
Если ЧтоДелать="Тестировать" Тогда
Результат=СформироватьОтчет();
Форма.Параметр = Результат;
Форма.Закрыть();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
|
- Третий способ нужно применять, когда кроме собственно результата хочется
вернуть еще какие-то значения (Тот же код ошибки, например).
Процедура ПриОткрытии()
Условия=Форма.Параметр;
Если ТипЗначенияСтр(Условия)="СписокЗначений" Тогда
ДатаС=Условия.Получить("ДатаС");
ДатаПо=Условия.Получить("ДатаПо");
ВыбФирма=Условия.Получить("ВыбФирма");
ЧтоДелать=Условия.Получить("ЧтоДелать");
Если ЧтоДелать="Тестировать" Тогда
Результат=СформироватьОтчет();
Пром = СоздатьОбъект("СписокЗначений");
Пром.ДобавитьЗначение(Результат, "ПолученныйРезультат");
Пром.ДобавитьЗначение(0, "КодОшибки");
Форма.Параметр = Пром;
Форма.Закрыть();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
|
Строки "ПолученныйРезультат" и "КодОшибки" - на данный момент единственные, которые
распознаются FuncTest'ом.
Последний штрих
Подготовив таким образом отчет для
тестирования - вы обязательно столкнетесь с проблемами, когда попробуете
запустить одновременно два теста одного отчета с разными параметрами.
Проблема будет заключаться в том, что запустившись во второй раз - он тем не
менее будет использовать параметры первого своего запуска. Происходит это
из-за того, что оператор Форма.Закрыть() закрывает форму не сразу, а после
того, как отработает весь модуль (а иначе как бы мы обратились к контексту
уже закрытой формы?).
Есть два способа решить эту проблему.
- Добавить в отчет процедуру ПриПовторномОткрытии() и в ней вызвать тот
же код анализа входных параметров, что и в процедуре ПриОткрытии(). В таком
случае код этих процедур выглядит примерно так:
Процедура АвтоТестирование(ВхУсловия)
Если ТипЗначенияСтр(Форма.Параметр) <> "СписокЗначений" Тогда
Возврат;
КонецЕсли;
ДатаС=Условия.Получить("ДатаС");
ДатаПо=Условия.Получить("ДатаПо");
ВыбФирма=Условия.Получить("ВыбФирма");
ЧтоДелать=Условия.Получить("ЧтоДелать");
Если ЧтоДелать="Тестировать" Тогда
Результат=СформироватьОтчет();
Результат.Выгрузить(ПолученныйРезультат);
Форма.Закрыть();
КонецЕсли;
КонецПроцедуры
Процедура ПриОткрытии()
Форма.ИспользоватьСлой("Основной",2);
АвтоТестирование(Форма.Параметр);
КонецПроцедуры
Процедура ПриПовторномОткрытии()
АвтоТестирование(Форма.Параметр);
КонецПроцедуры
|
- Открыть столько окон с отчетами, сколько нам нужно. Для
этого в браузере тестов, в поле "Объект тестирования" после пути к отчету
нужно добавить символ "#".
В заключение добавлю, что лично мне нравится первый способ, как использующий
хоть и незначительно, но все же меньшее количество памяти. :)
Готовый и полезный пример.
Можно скачать Оборотно-сальдовую ведомость, подготовленную для
автоматического тестирования.
Назад
Содержание
Далее
|