Персональная страница Федора Езеева
Главная
Download
Ссылки
MS SQL
Обмен данными
Новости
Статьи
О себе
Крупные разделы...
Коллективная разработка
1С++, OOP, XP
FuncTest
FAQ
Структура 1cv7.md
Назад Содержание Далее

FuncTest. Как тестировать отчеты

Небольшая вводная.

Для начала.

Для начала - две новости, одна хорошая, вторая плохая. Сначала плохая. Произвольный отчет протестировать не получится. Прежде чем отчет можно будет тестировать - он должен быть соответствующим образом написан/поправлен. Теперь хорошая новость. С версии 0.9.9 Фанктест научился сравнивать печатные формы, а это значит, что любой отчет можно достаточно оперативно подготовить для тестирвоания.

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

Основная идея.

Основная идея тестирования заключается в том, что мы сравниваем наше ожидание с действительно полученным результатом. Основная проблема тестирования отчетов заключается в том, что мы - люди, и наше ожидание от отчета является некоторой печатной формой. Здесь нужно совершить некоторое насилие над собой и разделить логику формирования отчета на две части. (Это разделение нужно сделать и у себя в голове, и в коде отчета:). Первая часть будет формировать набор данных, составляющих суть отчета, вторая часть будет выводить этот набор данных на экран/принтер. Следующий шаг: если от отчета ожидать не печатную форму, а набор данных, то такое ожидание гораздо проще протестировать.

Мы умеем выражать наши ожидания в виде Таблицы Значений. Если отчет тоже сможет возвращать Таблицу Значений мы сможем сравнить эти таблицы. Это и будет тестированием отчета. Более того, сложные отчеты зачастую именно так и формируются: разноплановые данные собираются в Таблицу Значений, в ней сортируются, фильтруются, группируются, и только потом выводятся на экран.

Пример.

С чего начнем.

Чтобы не стало слишком скучно от голословных утверждений - приведу маленький пример доработки отчета. Пример действительно маленький, и кому-то может показаться, что тестировать его - только время терять. Не будьте строгими - это просто пример. Отчет называется "Реестр Счетов". Для всех проведенных счетов за указанный период времени по указанной фирме этот реестр выводит дату, номер, название клиента и сумму счета. Модуль его процедуры Сформировать() такой:

Т=СоздатьОбъект("Таблица");
Т.ВывестиСекцию("Шапка");

Сч=СоздатьОбъект("Документ.Счет");
//ДатаС и ДатаПо - реквизиты на форме отчета
Сч.ВыбратьДокументы(ДатаС,ДатаПо);
Пока Сч.ПолучитьДокумент()=1 Цикл
	Если Сч.Проведен()=0 Тогда
		Продолжить;
	КонецЕсли;
	//ВыбФирма - реквизит на форме отчета
	Если Сч.Фирма<>ВыбФирма Тогда
		Продолжить;
	КонецЕсли;
	
	//Все необходимые вычисления происходят в печатной форме отчета
	Т.ВывестиСекцию("Строка");
КонецЦикла;
Т.ВывестиСекцию("Подвал");
Т.Показать();

Результат отчета - в таблицу значений.

Для начала я создам Таблицу Значений, куда сложу данные отчета. В этом (простом) случае эта таблица вполне может содержать одну колонку "Счет" типа "Документ.Счет". До всех нужных реквизитов счета я доберусь уже на стадии вывода на печать. Теперь модуль такой (изменения выделены жирным):

Отчет=СоздатьОбъект("ТаблицаЗначений");
Отчет.НоваяКолонка("Счет");

Т=СоздатьОбъект("Таблица");
Т.ВывестиСекцию("Шапка");

Сч=СоздатьОбъект("Документ.Счет");
Сч.ВыбратьДокументы(ДатаС,ДатаПо);
Пока Сч.ПолучитьДокумент()=1 Цикл
	Если Сч.Проведен()=0 Тогда
	Продолжить;
	КонецЕсли;
	Если Сч.Фирма<>ВыбФирма Тогда
		Продолжить;
	КонецЕсли;

	Отчет.НоваяСтрока();
	Отчет.Счет=Сч.ТекущийДокумент();
	
	Т.ВывестиСекцию("Строка");
КонецЦикла;
Т.ВывестиСекцию("Подвал");
Т.Показать();

Данные для печати - из таблицы значений.

Теперь нужно переработать кусочек вывода на экран так, чтобы данные брались из Таблицы "Отчет". Более того - эту часть кода я выделю в отдельную процедуру.

Процедура НапечататьОтчет(Отчет)

Т=СоздатьОбъект("Таблица");
Т.ВывестиСекцию("Шапка");

Отчет.ВыбратьСтроки();
Пока Отчет.ПолучитьСтроку()=1 Цикл
	Т.ВывестиСекцию("Строка");
	//В секции "Строка" нужно поменять обращения к переменной Сч на выражение Отчет.Счет
КонецЦикла;

Т.ВывестиСекцию("Подвал");
Т.Показать();

КонецПроцедуры()

Процедура Сформировать()

Отчет=СоздатьОбъект("ТаблицаЗначений");
Отчет.НоваяКолонка("Счет");

Сч=СоздатьОбъект("Документ.Счет");
Сч.ВыбратьДокументы(ДатаС,ДатаПо);
Пока Сч.ПолучитьДокумент()=1 Цикл
	Если Сч.Проведен()=0 Тогда
		Продолжить;
	КонецЕсли;
	Если Сч.Фирма<>ВыбФирма Тогда
		Продолжить;
	КонецЕсли;

	Отчет.НоваяСтрока();
	Отчет.Счет=Сч.ТекущийДокумент();
КонецЦикла;

//Закончилось формирование таблицы отчета - выведем ее на экран.
НапечататьОтчет(Отчет);

КонецПроцедуры

Простой рефакторинг.

Теперь мне нужно, чтобы Таблицу Значений "Отчет" я смог получить и из других процедур своего отчета. Это просто - весь текст процедуры Сформировать() до комментария я выделяю в функцию СформироватьОтчет(), которая формирует Таблицу и возвращает ее значение. Теперь процедура Сформировать() состоит из одной строки:

Процедура Сформировать()
	НапечататьОтчет(СформироватьОтчет());
КонецПроцедуры

Ключевой момент.

Теперь вкусное. Я хочу использовать свой отчет, как функцию. Во-первых, мне нужно передать начальные параметры (значения реквизитов формы ДатаС, ДатаПо и ВыбФирма); и во-вторых, отчет должен вернуть мне таблицу значений с данными отчета. FuncTest понимает три варианта отчетов-функций.

  1. Первая техника превращения отчета в функцию нагло позаимствована на сайте http://e1s.chat.ru.

    На форме отчета размещается ТаблицаЗначений (я даю этой таблице имя "ПолученныйРезультат"). В процедуре ПриОткрытии() анализирую параметр. Я хочу, чтобы мне здесь дали Список Значений, такой, чтобы у значения, где лежит, например, значение фирмы - представление было "ВыбФирма". Вот текст процедуры:

    Процедура ПриОткрытии()
    
    Условия=Форма.Параметр;
    Если ТипЗначенияСтр(Условия)="СписокЗначений" Тогда
    	ДатаС=Условия.Получить("ДатаС");
    	ДатаПо=Условия.Получить("ДатаПо");
    	ВыбФирма=Условия.Получить("ВыбФирма");
    	ЧтоДелать=Условия.Получить("ЧтоДелать");
    	Если ЧтоДелать="Тестировать" Тогда
    		Результат=СформироватьОтчет();
    		Результат.Выгрузить(ПолученныйРезультат);
    		КодОшибки = 0; // это тоже реквизит на форме
    		Форма.Закрыть();
    	КонецЕсли;
    КонецЕсли;
    
    КонецПроцедуры
    

    В качестве небольшого дополнения. FuncTest предполагает, что в отчете есть еще числовое поле с идентификатором "КодОшибки", в котором 0, если все хорошо, и не 0, если случилась какая-то исключительная ситуация (см. комментарий в модуле).

    Я создал для себя параметр "ЧтоДелать" - в дальнейшем это позволит мне малой ценой расширить возможности этого отчета. Я смогу его сформировать по переданным условиям, или просто открыть, автоматически заполнив реквизиты, да мало ли что еще.

  2. Второй способ - намного проще первого, поскольку не требует размещения на форме дополнительных реквизитов.
    Процедура ПриОткрытии()
    
    Условия=Форма.Параметр;
    Если ТипЗначенияСтр(Условия)="СписокЗначений" Тогда
    	ДатаС=Условия.Получить("ДатаС");
    	ДатаПо=Условия.Получить("ДатаПо");
    	ВыбФирма=Условия.Получить("ВыбФирма");
    	ЧтоДелать=Условия.Получить("ЧтоДелать");
    	Если ЧтоДелать="Тестировать" Тогда
    		Результат=СформироватьОтчет();
    		Форма.Параметр = Результат;
    		Форма.Закрыть();
    	КонецЕсли;
    КонецЕсли;
    
    КонецПроцедуры
    
  3. Третий способ нужно применять, когда кроме собственно результата хочется вернуть еще какие-то значения (Тот же код ошибки, например).
    Процедура ПриОткрытии()
    
    Условия=Форма.Параметр;
    Если ТипЗначенияСтр(Условия)="СписокЗначений" Тогда
    	ДатаС=Условия.Получить("ДатаС");
    	ДатаПо=Условия.Получить("ДатаПо");
    	ВыбФирма=Условия.Получить("ВыбФирма");
    	ЧтоДелать=Условия.Получить("ЧтоДелать");
    	Если ЧтоДелать="Тестировать" Тогда
    		Результат=СформироватьОтчет();
    		Пром = СоздатьОбъект("СписокЗначений");
    		Пром.ДобавитьЗначение(Результат, "ПолученныйРезультат");
    		Пром.ДобавитьЗначение(0, "КодОшибки");
    		Форма.Параметр = Пром;
    		Форма.Закрыть();
    	КонецЕсли;
    КонецЕсли;
    
    КонецПроцедуры
    
    Строки "ПолученныйРезультат" и "КодОшибки" - на данный момент единственные, которые распознаются FuncTest'ом.

    Последний штрих

    Подготовив таким образом отчет для тестирования - вы обязательно столкнетесь с проблемами, когда попробуете запустить одновременно два теста одного отчета с разными параметрами. Проблема будет заключаться в том, что запустившись во второй раз - он тем не менее будет использовать параметры первого своего запуска. Происходит это из-за того, что оператор Форма.Закрыть() закрывает форму не сразу, а после того, как отработает весь модуль (а иначе как бы мы обратились к контексту уже закрытой формы?).

    Есть два способа решить эту проблему.

    1. Добавить в отчет процедуру ПриПовторномОткрытии() и в ней вызвать тот же код анализа входных параметров, что и в процедуре ПриОткрытии(). В таком случае код этих процедур выглядит примерно так:
      Процедура АвтоТестирование(ВхУсловия)
      	Если ТипЗначенияСтр(Форма.Параметр) <> "СписокЗначений" Тогда
      		Возврат;
      	КонецЕсли;
      	ДатаС=Условия.Получить("ДатаС");
      	ДатаПо=Условия.Получить("ДатаПо");
      	ВыбФирма=Условия.Получить("ВыбФирма");
      	ЧтоДелать=Условия.Получить("ЧтоДелать");
      	Если ЧтоДелать="Тестировать" Тогда
      		Результат=СформироватьОтчет();
      		Результат.Выгрузить(ПолученныйРезультат);
      		Форма.Закрыть();
      	КонецЕсли;
      КонецПроцедуры
      
      Процедура ПриОткрытии()
      	Форма.ИспользоватьСлой("Основной",2);
      	АвтоТестирование(Форма.Параметр);
      КонецПроцедуры
      
      Процедура ПриПовторномОткрытии()
      	АвтоТестирование(Форма.Параметр);
      КонецПроцедуры
      
    2. Открыть столько окон с отчетами, сколько нам нужно. Для этого в браузере тестов, в поле "Объект тестирования" после пути к отчету нужно добавить символ "#".
    В заключение добавлю, что лично мне нравится первый способ, как использующий хоть и незначительно, но все же меньшее количество памяти. :)

    Готовый и полезный пример.

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


    Назад Содержание Далее
Rambler's Top100 1C:TOP-100

© 1998-2004 Fedor Ezeev.

Last updated: 2008-03-27