« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга


ПнВтСрЧтПтСбВс
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
    Популярное
Пользователь или схема?

Глава 3. Устанавливаем Linux Mandrake 7.0/RE

Основы полнотекстового поиска

Определение свойств окна проекта

Компонент программиста

Функция GetActiveWindow

Обобщенные Вектора

Функция AccessResource

Компоненты Indy, применяемые в Delphi

Программирование на управляемом C++




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 205
Пользователей: 0

Статьи:: Тестирование :: Автоматизация тестирования для Delphi



отправить ссылку другу версия для печати  Обсудить на форуме

Автоматизация тестирования для Delphi



© 2002 Войнов Николай

Вы когда-нибудь сталкивались с проблемами при тестировании ваших программ? Если нет – то Вы либо супер-профессионал, либо не писали больших программ, либо не цените Ваше время. Из многочисленных печатных источников по разработке программного обеспечения (ПО), говорится, что фаза тестирования занимает 40% трудозатрат по проекту создания ПО.

Как-то при разработке ПО движения товаров, включающее в себя большое кол-во функций, возникло много проблем: то реакция на событие не работает, то ПО выполняет не то, что от него ожидаешь, … . Всего не упомнишь. ПО было разработано, но затраченные усилия не оправдали себя. Урок состоялся. Поэтому было решено взять небольшой таймаут и подумать о средствах устранения проблем. Самым простым выходом из этой ситуации было включение тестирования в процесс разработки.

Об автоматизированном тестировании программ до этого я знал лишь понаслышке. Буквально следующее: "программа для тестирования InterBase в десятки раз превышает размер самого InterBase".

И был еще "Delphi 6 Campaign CD", приобретенный около полугода назад, на котором присутствовало средство для автоматизированного тестирования – DUnit, библиотека классов, предназначенная для поддержки тестирования программ, принятых в экстремальном программировании и пподдерживающая Delphi4 и выше.

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

DUnit предлагает классы, которые позволяют вам просто организовать и выполнить созданные вами тесты. Предлагаются две опции для запуска ваших тестов:

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

DUnit была создана на основе библиотеки JUnit, разработанной Кеннетом Беком(Kent Beck) и Эрихом Гамма(Erich Gamma) для языка Java, которая превратилась в мощный инструмент, для программирования на Delphi. Оригинальный порт под Delphi был сделан Juanco Anez и в настоящее время поддерживается DUnit Group на SourceForge.

Кто заинтересовался, может идти сразу на домашнюю страницу DUnit и скачивать библиотеку: DUnit homepage at SourceForge.

Почитал Readme, посмотрел примеры – вдохновляет. Решено было сделать небольшой пилотный проект, уж очень хотелось опробовать автоматизированное тестирование и проверить несколько новых идей в реализации интерфейса.

В основном занимаюсь разработкой ПО, предназначенного для автоматизации складкой деятельности решено было сделать нечто такое, что пригодилось бы мне в повседневной деятельности. Для демонстрации тестирования с библиотекой DUnit была создана программа SalesMgr. Если вы читали Ксавье и Пачеко Delphi Developers Guide и дошли до главы 33 – то однозначно найдете много общего. Есть четыре формы Склад, Клиенты, Новая продажа и архив продаж. Использовались сервер FireBird( +FibPlus). Кроме того, хотелось попробовать контролы из DECOSP Lib.

Программа выполняет следующие действия

и упрощенно имеет следующую структуру

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

Посмотрим, чем нам может помочь DUnit. Все мы тестировать не будем, ограничимся основными операциями.

При создании подобных программ, я всегда делаю шаблон проекта, в который входит модуль данных, занимающийся подключением к БД и хранением глобальных переменных. Повторное использование? Тогда можно попробовать повторно использовать и тесты.

Итак, займемся последовательным тестированием модулей:

  1. TFibDataModule
    • Login
    • Logout
  2. TSalesDataModule
    • NewSale
    • SaveSale
  3. TfrmNewSale
    • EnabledOp
    • sbAcceptClick
    • sbCancelClick

Чем нам может помочь DUnit? В каталоге ContribXPGen был обнаружен кодогенератор! Всего за пару минут можно сделать шаблон теста для модуля. Простая, но полезная утилитка, экономит массу времени.

Надеюсь, вы уже посмотрели Readme к DUnit, поэтому не будем отвлекаться на основных моментах.

Итак, запускаем XPGen и подаем ему на вход dmFib.pas(TFibDataModule), немного правим и получаем код для тестирования функций dmFib:

unit Test_dmFib;
interface
uses
    TestFramework, SysUtils, Forms, dmFib;

type
    CRACK_TFibDataModule = class(TFibDataModule);
    Check_TFibDataModule = class(TTestCase)
    private
        DM: TFibDataModule;
    public
        //это для иннициализации тестов
        procedure setUp; override;
        procedure tearDown; override;
    published
        //это непосредственно тесты
        procedure VerifyLogin;
        procedure VerifyLogout;
    end;

function Suite : ITestSuite;

implementation

function Suite : ITestSuite;
begin
    result := TTestSuite.Create('dmFib Tests');
    // result.addTest(Check_TFibDataModule); почему-то не работает, хотя сгенерировано автомат.
end;
procedure Check_TFibDataModule.setUp;
begin
    DM := TFibDataModule.Create(Application);
end;
procedure Check_TFibDataModule.tearDown;
begin
    DM.Free;
end;

procedure Check_TFibDataModule.VerifyLogin;
begin
    DM.Login;
    Check(DM.dbFib.Connected = True, 'Login failure!');
end;
procedure Check_TFibDataModule.VerifyLogout;
begin
    DM.Login; DM.Logout;
    Check(not DM.dbFib.Connected, 'Logout failure!');
end;
initialization
    TestFramework.RegisterTest('dmFib', Check_TFibDataModule.Suite);
end.

Код проекта:

program AutoTestPrj;
uses
    Forms,
    TestFrameWork,
    GUITestRunner,
    Test_dmFib in 'Test_dmFib.pas',
    dmFib in '..CommonFilesdmFib.pas' {FibDataModule: TDataModule},
    common in '..commonfilescommon.pas',
    Test_dmSales in 'Test_dmSales.pas';
{$R *.res}
begin
    Application.Initialize;
    GUITestRunner.RunRegisteredTests;
end.

Запускаем и видим:

Нажимаем на всем знакомую зеленую треугольную кнопочку и получаем первый автоматизированный тест! Думаю, проблем пока не возникло? У меня это получилось после часа изучения демок к библиотеке (у меня был готовый шаблон проекта, поэтому получилось так быстро).

А для тестирования функций TsalesDataModule придется немного повозиться. Это связано с инициализацией входных данных.

unit Test_dmSales;

interface

uses
    TestFramework,
    SysUtils,
    Forms,
    dmSales;

type

CRACK_TSalesDataModule = class(TSalesDataModule);

Check_TSalesDataModule = class(TTestCase)
    public
        procedure setUp; override;
        procedure tearDown; override;
    published
        procedure VerifyNewSale;
end;

function Suite : ITestSuite;

implementation

uses dmAttr, dmFib;

function Suite : ITestSuite;
begin
    result := TTestSuite.Create('dmSales Tests');
    // result.addTest(testSuiteOf(Check_TSalesDataModule));
end;

procedure Check_TSalesDataModule.setUp;
var ctg: Integer; meas: string;
begin
    FibDataModule := TFibDataModule.Create(Application);
    AttrDataModule := TAttrDataModule.Create(Application);
    SalesDataModule := TSalesDataModule.Create(Application);
    FibDataModule.Login;

    { TODO 1 -cDUnit_TEST : добавить тестовые ед.изм. и категории }
    AttrDataModule.OpenAttrs;
    if AttrDataModule.dtSection.RecordCount = 0 then
        AttrDataModule.__InsCatg('Test_Catg');
    if AttrDataModule.dtMeasure.RecordCount = 0 then
        AttrDataModule.__InsMeas('TESTMEA');

    ctg := AttrDataModule.GetCatgId;
    meas:= AttrDataModule.GetMeasure;

    { TODO 1 -cDUnit_TEST : добавить тестовое наличие товара на складе }
    SalesDataModule.OpenPart;
    SalesDataModule.__InsPart(1,ctg,'Part Position 1',50,5,6,meas);
    SalesDataModule.__InsPart(1,ctg,'Part Position 2',50,5,6,meas);
    SalesDataModule.__InsPart(1,ctg,'Part Position 3',50,5,6,meas);
    SalesDataModule.__InsPart(1,ctg,'Part Position 4',50,5,6,meas);
    SalesDataModule.__InsPart(1,ctg,'Part Position 5',50,5,6,meas);

    { TODO 1 -cDUnit_TEST : добавить тестовых покупателей }
    meas := DateToStr(Now);
    SalesDataModule.OpenCust;
    SalesDataModule.__InsCust(1,'Customer 1 '+meas,0,'Test Customer 1');
    SalesDataModule.__InsCust(1,'Customer 2 '+meas,0,'Test Customer 2');

    FibDataModule.CommitRetainingAll;
end;

procedure Check_TSalesDataModule.tearDown;
begin
    FibDataModule.Logout;
    SalesDataModule.Free;
    AttrDataModule.Free;
    FibDataModule.Free;
end;

////////////////////////////////////////////////////////////////////////////////
procedure Check_TSalesDataModule.VerifyNewSale;
begin
    with SalesDataModule do begin
        NewSale; //добавляем по единице каждого товара
        Check(dtPrice.RecordCount <> 0, 'нечего продавать');
        if dtPrice.RecordCount = 0 then Exit;
        dtPrice.First;
        while not dtPrice.Eof do begin
            dtPrice.Edit;
            dtPrice.FBN('QTY').AsInteger := 1;
            dtPrice.Next;
        end;
        SaveNewSale(Now, DateToStr(Now) + ' Test_dmSales');
        CloseNewSale;
        //ищем нашу новую продажу
        OpenSales; dtSales.Last;
        Check(dtSales.FBN('DESCR').AsString = DateToStr(Now) + ' Test_dmSales','NewSale failure!');
    end;
end;

initialization
    TestFramework.RegisterTest('dmSales', Check_TSalesDataModule.Suite);
end.

И, наконец, протестируем интерфейс! Для этого пришлось покопаться в UnitTestGUITesting.pas, так как в примерах этого не было. Все как обычно – запускаем XPGen, даем ему на вход fmNewSale.pas, подправляем немного в соответствии нашими целями.

unit Test_fmNewSale;
interface
uses
    TestFramework,
    GUITesting,
    GUITestRunner,
    SysUtils,
    Graphics,
    Windows,
    Classes,
    Forms,
    fmNewSale;

type
    CRACK_TfrmNewSale = class(TfrmNewSale);
    Check_TfrmNewSale = class(TGUITestCase)
        private
             NewSaleFrm: TfrmNewSale;
        public
            procedure setUp; override;
            procedure tearDown; override;
        published
            procedure VerifyEnabledOp;
            procedure VerifysbAcceptClick;
            procedure VerifysbCancelClick;
end;

function Suite : ITestSuite;

implementation

uses common, dmAttr, dmFib, dmSales, fmFilter, FrActionFrm;

function Suite : ITestSuite;
begin
    result := TTestSuite.Create('fmNewSale Tests');
end;

procedure Check_TfrmNewSale.setUp;
begin
    inherited;
    FibDataModule := TFibDataModule.Create(nil);
    AttrDataModule := TAttrDataModule.Create(nil);
    SalesDataModule := TSalesDataModule.Create(nil);
    FibDataModule.Login;
    SalesDataModule.OpenCust;

    NewSaleFrm := TfrmNewSale.Create(nil);
    GUI := NewSaleFrm;
end;

procedure Check_TfrmNewSale.tearDown;
begin
    GUI := nil;
    NewSaleFrm.Free;
    inherited;
end;

procedure Check_TfrmNewSale.VerifyEnabledOp;
begin
    Show;
    Check(NewSaleFrm.sbAccept.Enabled = False, 'можно произвести пустую операцию ?');
    Check(NewSaleFrm.sbCancel.Enabled = False, 'можно отменить пустую операцию ?');
    SalesDataModule.dtPrice.Edit;
    SalesDataModule.dtPrice.FBN('QTY').AsInteger := 0;
    SalesDataModule.dtPrice.Post;
    Check(NewSaleFrm.sbAccept.Enabled = False, 'можно произвести пустую операцию ?');
    Check(NewSaleFrm.sbCancel.Enabled = False, 'можно отменить пустую операцию ?');
end;

procedure Check_TfrmNewSale.VerifysbAcceptClick;
begin
    Show;
    Check(NewSaleFrm.AddingOp = False, 'пустая операция ?');
    SalesDataModule.dtPrice.Edit;
    SalesDataModule.dtPrice.FBN('QTY').AsInteger :=1;
    SalesDataModule.dtPrice.Post;
    Check(NewSaleFrm.AddingOp, 'непустая операция ?');
    NewSaleFrm.sbAccept.Click;
    Check(NewSaleFrm.AddingOp = False, 'пустая операция ?');
end;

procedure Check_TfrmNewSale.VerifysbCancelClick;
begin
    Show;
    Check(NewSaleFrm.AddingOp = False, 'пустая операция ?');
    SalesDataModule.dtPrice.Edit;
    SalesDataModule.dtPrice.FBN('QTY').AsInteger :=1;
    SalesDataModule.dtPrice.Post;
    Check(NewSaleFrm.AddingOp, 'непустая операция ?');
    NewSaleFrm.sbCancel.Click;
    Check(NewSaleFrm.AddingOp = False, 'пустая операция ?');
end;

initialization
    TestFramework.RegisterTest('NewSale', Check_TfrmNewSale.Suite);
end.

Пришлось немного переделать свою форму-шаблон, так и не смог справиться со стандартными диалогами, которые создаются методом MessageDlg.

Окончательно проект принял такой вид:

program AutoTestPrj;
uses
    Forms,
    TestFrameWork,
    GUITestRunner,
    Test_dmFib in 'Test_dmFib.pas',
    dmFib in '..CommonFilesdmFib.pas' {FibDataModule: TDataModule},
    common in '..commonfilescommon.pas',
    dmSales in '..SalesMgrdmSales.pas' {SalesDataModule: TDataModule},
    dmAttr in '..commonfilesdmAttr.pas' {AttrDataModule: TDataModule},
    fmFilter in '..commonfilesfmFilter.pas' {frmInvFilter},
    FrActionFrm in '..commonfilesFrActionFrm.pas' {FrActionForm},
    fmNewSale in '..SalesMgrfmNewSale.pas' {frmNewSale},
    OpTemplateFrm in '..commonfilesOpTemplateFrm.pas' {OpTemplateForm},
    ChildFrm in '..commonfilesChildFrm.pas' {ChildForm},
    ItemsFm in '..commonfilesItemsFm.pas' {ItemsFrame: TFrame},
    Test_dmSales in 'Test_dmSales.pas',
    Test_fmNewSale in 'Test_fmNewSale.pas';

{$R *.res}

begin
    Application.Initialize;
    GUITestRunner.RunRegisteredTests;
end.

Запускайте тест, смотрите. Если, кто продвинется до тестирования диалогов (клацания кнопок на диалогах) – поделитесь информацией.




Рубрика: Тестирование




Вышел MySQL 5.1.30, первый стабильный рели....

MySQL

После публикации 29 тестовых версий анонсирован первый стабильный релиз MySQL 5.1, пригодный для промышленной эксплуатации и обеспечивающий увеличение производительности для "тяжелых" SQL запросов, по сравнению с MySQL 5.0, примерно на 15-20%. Главные новшества появившиеся в MySQL 5.1:


Подробнее... | Рубрика: MySQL | Добавлено: 28.11.2008

Тестирование параллельных программ.

Тестирование

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


Подробнее... | Рубрика: Тестирование | Добавлено: 28.11.2008

Архитектура AMD64 (EM64T).

Архитектура AMD

Аннотация. В статье кратко рассматривается архитектура AMD64 компании AMD и ее реализация EM64T компании Intel. Описаны особенности архитектуры, ее возможности, достоинства и недостатки.


Подробнее... | Рубрика: Архитектура AMD | Добавлено: 27.11.2008

Остальные статьи:

Платформа 2009. Определяя будущее
Windows Vista Bridge Sample Library - упра...
Оптимизация 64-битных программ
Подгрузка через AJAX HTML-кода, содержащег...
Обзор нового релиза самой мощной Ajax библ...
Firebug 1.3 и 1.4 alpha — что нового и инт...
Релиз Microsoft Silverlight 2.0. Что новог...
XML документация в C#
Курсоры в MySQL 5
Microsoft опубликовала подробности о сесси...
Microsoft делится подробностями о том, что...
Тестируем новый javascript от нового брауз...
MySQL Query Cache
Использование провайдеров компиляции в As...
Чего мы ждем от C# 4.0
Delphi 2009 и C++Builder 2009
Джоэл Спольски и Джеф Этвуд запустили новы...
Поиск кода Google /* что нового? */
10 jQuery скриптов для улучшения интерфейс...
Генераторы отчетов FastReport 4 и QuickRep...


Цитата дня (все,добавить):

Портал фрилансеров

работа на дому


    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование


Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия