Отвлечёмся немного от "хардкорного программирования" и устройства скриптовой машины.
Вот тут - http://18delphi.blogspot.ru/2013/11/gui.html - я писал как искать форму и контрол по их имени
А вот тут - http://18delphi.blogspot.ru/2013/11/gui_4.html - я писал - как в TEdit ввести текст.
А вот тут - http://18delphi.blogspot.ru/2013/11/gui-rtti.html - я писал как сделать "то же самое" средствами "классического" RTTI.
Напомню, что у нас в итоге получилось:
Теперь пусть мы опять же хотим поработать с контролом в фокусе, но при этом мы хотим проконтролировать, что контрол в фокусе - НУЖНОГО нам класса - TEdit или TCustomEdit, ну или наследник он него.
Ну скажем - логика теста зависит от этого.
Как это сделать?
Сейчас расскажу.
Напишем для начала два "вспомогательных" слова.
Они - в ПРИНЦИПЕ полезны для GUI-Тестирования.
Но и ещё они помогут нам расширить наши примеры.
Вот эти слова:
Про слово WORDWORKER я писал тут - http://18delphi.blogspot.ru/2013/11/gui_9015.html и тут - http://18delphi.blogspot.ru/2013/11/gui-2_7.html
Тогда наш пример переписывается так:
Конкатенативный язык (http://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%BA%D0%B0%D1%82%D0%B5%D0%BD%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F).
Не правда ли?
Теперь КАК определить, что "Контрол в фокусе" - НУЖНОГО нам класса?
А вот как:
На стороне Delphi определяем слово Inherits:
Тогда можно написать такой код скрипта:
Ну или такой:
Поработаем ещё немного.
Введём в словарь определение вот такого слова:
Тогда можно написать так:
Ещё несколько штрихов.
Для начала определим слово ЯВЛЯЕТСЯ:
Тогда можно написать так:
Ещё определим синоним:
Тогда можно написать так:
Ещё немного поработаем над IF.
У нас помимо слова WORDWORKER - есть слово WORDWORKER2.
Которое умеет работать с двумя "параметрами справа".
Применим его.
Напишем следующее:
И тогда наш пример можно переписать так:
По-русски? По-моему - по русски?
Теперь если определить слово "то":
Так:
Или так:
То мы можем переписать пример так:
Ну и ещё введём синоним:
Тогда можно написать так:
Ну и "на закуску".
Ещё есть слово WORDWORKER2+.
Оно умеет работать с двумя фиксированными "параметрами справа".
И одним опциональным. Предварённым другим ключевым словом.
Вот пример:
Тогда можно написать так:
По-моему - "уже перебор информации".
Поэтому - закругляюсь.
Чуть позже я расскажу - как регистрировать РЕАЛЬНЫЕ классы объектов в тестовой машине, чтобы работать с их идентификаторами, а не со "строковыми именами".
И БОЛЕЕ ТОГО - вызывать их КОНСТРУКТОРЫ. Т.е. на самом деле - скриптовая машина - МОЖЕТ обладать возможностью СОЗДАВАТЬ объекты реального приложения.
Неплохо для "тестовой машины", а?
На самом деле - наверное самые пытливые читатели отметили, для себя, что эту скриптовую машину можно использовать не только для тестирования, но и для АВТОМАТИЗАЦИИ и написания макросов пользователя.
Такой вот VBA (http://ru.wikipedia.org/wiki/VBA) "на коленке".
Если компилировать "скриптовую обвязку" не только под IfDef Test, но и для конечного клиентского приложения.
И ДАТЬ пользователю возможность загружать и выполнять скрипты.
P.S. Я ещё вас не утомил? А то у меня план статей разросся уже до 30-ти штук.
Кому-то вообще интересно "сделать скриптовую машину своими руками" из "модели для сборки"?
Или пора закругляться?
Учитывая, что каждая новая статья приносит с собой ещё две статьи в "план для написания".
Вот тут - http://18delphi.blogspot.ru/2013/11/gui.html - я писал как искать форму и контрол по их имени
А вот тут - http://18delphi.blogspot.ru/2013/11/gui_4.html - я писал - как в TEdit ввести текст.
А вот тут - http://18delphi.blogspot.ru/2013/11/gui-rtti.html - я писал как сделать "то же самое" средствами "классического" RTTI.
Напомню, что у нас в итоге получилось:
PROCEDURE "Присвоить текст в текущий контрол" STRING IN aText OBJECT VAR l_Control FocusedControl =: l_Control aText l_Control EditSetText END //"Присвоить текст в текущий контрол"
Теперь пусть мы опять же хотим поработать с контролом в фокусе, но при этом мы хотим проконтролировать, что контрол в фокусе - НУЖНОГО нам класса - TEdit или TCustomEdit, ну или наследник он него.
Ну скажем - логика теста зависит от этого.
Как это сделать?
Сейчас расскажу.
Напишем для начала два "вспомогательных" слова.
Они - в ПРИНЦИПЕ полезны для GUI-Тестирования.
Но и ещё они помогут нам расширить наши примеры.
Вот эти слова:
OBJECT FUNCTION "Контрол в фокусе" FocusedControl =: Result END // "Контрол в фокусе" WORDWORKER "Присвоить текст в" STRING IN aText OBJECT VAR l_Control WordToWork DO =: l_Control aText l_Control EditSetText END // "Присвоить текст в"
Про слово WORDWORKER я писал тут - http://18delphi.blogspot.ru/2013/11/gui_9015.html и тут - http://18delphi.blogspot.ru/2013/11/gui-2_7.html
Тогда наш пример переписывается так:
PROCEDURE "Присвоить текст в текущий контрол" STRING IN aText "Присвоить текст {(aText)} в" "Контрол в фокусе" END //"Присвоить текст в текущий контрол"
Конкатенативный язык (http://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%BA%D0%B0%D1%82%D0%B5%D0%BD%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F).
Не правда ли?
Теперь КАК определить, что "Контрол в фокусе" - НУЖНОГО нам класса?
А вот как:
На стороне Delphi определяем слово Inherits:
interface type TkwInherits = class(TscriptKeyWord) protected procedure DoIt(aContext: TscriptContext); override; end;//TkwInherits implementation procedure TkwInherits.DoIt(aContext: TscriptContext); var l_ClassName : String; function localIsInherits(anObjectClass : TClass): Boolean; begin if (anObjectClass = nil) then Result := false else if SameText(anObjectClass.ClassName, l_ClassName) then Result := true else Result := localIsInherits(anObjectClass.ClassParent); end; var l_Object : TObject; begin l_Object := aContext.PopObject; Assert(l_Object <> nil); l_ClassName := aContext.PopString; aContext.PushBoolean(localIsInherits(l_Object.ClassType)); end; initialization ScriptEngine.RegisterKeyWord(TkwInherits, 'Inherits'); // - далее, если вызов RegisterKeyWord будет в виде RegisterKeyWord(TkwXXX, 'XXX'), // то я буду просто так и писать RegisterKeyWord(TkwXXX). // // Тем более, что это у меня так и реализовано, через использование ClassName
Тогда можно написать такой код скрипта:
'TCustomEdit' "Контрол в фокусе" Inherits IF ( "Присвоить текст {(aText)} в" "Контрол в фокусе" )
Ну или такой:
'TCustomEdit' "Контрол в фокусе" Inherits ASSERT "Присвоить текст {(aText)} в" "Контрол в фокусе"
Поработаем ещё немного.
Введём в словарь определение вот такого слова:
CONST "Строка ввода" 'TCustomEdit'
Тогда можно написать так:
"Строка ввода" "Контрол в фокусе" Inherits IF ( "Присвоить текст {(aText)} в" "Контрол в фокусе" )
Ещё несколько штрихов.
Для начала определим слово ЯВЛЯЕТСЯ:
BOOLEAN WORDWORKERFUNCTION ЯВЛЯЕТСЯ OBJECT IN anObject WordToWork DO // - вычисляем "параметр справа" anObject // - anObject - "параметр слева" Inherits // - зовём уже знакомое нам слово Inherits =: Result // - результат нашиз вычислений помещаем в результат функциии ЯВЛЯЕТСЯ END // ЯВЛЯЕТСЯ
Тогда можно написать так:
"Контрол в фокусе" ЯВЛЯЕТСЯ "Строка ввода" IF ( "Присвоить текст {(aText)} в" "Контрол в фокусе" )
Ещё определим синоним:
WordAlias "Строкой ввода" "Строка ввода"
Тогда можно написать так:
"Контрол в фокусе" ЯВЛЯЕТСЯ "Строкой ввода" IF ( "Присвоить текст {(aText)} в" "Контрол в фокусе" )
Ещё немного поработаем над IF.
У нас помимо слова WORDWORKER - есть слово WORDWORKER2.
Которое умеет работать с двумя "параметрами справа".
Применим его.
Напишем следующее:
WORDWORKER2 если WordToWork1 DO // - вычислили значение "первого аргумента справа" IF ( WordToWork2 DO // - выполняем "второй аргумент справа" ) END // если
И тогда наш пример можно переписать так:
если ( "Контрол в фокусе" ЯВЛЯЕТСЯ "Строкой ввода") ( "Присвоить текст {(aText)} в" "Контрол в фокусе" )
По-русски? По-моему - по русски?
Теперь если определить слово "то":
Так:
WordAlias то NOP // - NOP - это слово, которое ничего не делает, // но может появляться там, где грамматика требует слово
Или так:
WORDWORKER то WordToWork DO // - просто вычисляем "аргумент справа" // т.е. слово "то" в данном случае является proxy-словом END // то
То мы можем переписать пример так:
если ( "Контрол в фокусе" ЯВЛЯЕТСЯ "Строкой ввода") то ( "Присвоить текст {(aText)} в" "Контрол в фокусе" )
Ну и ещё введём синоним:
WordAlias Если если // - у нас скриптовая машина - РЕГИСТРОЗАВИСИМАЯ, это - ОСОЗНАННО
Тогда можно написать так:
Если ( "Контрол в фокусе" ЯВЛЯЕТСЯ "Строкой ввода") то ( "Присвоить текст {(aText)} в" "Контрол в фокусе" )
Ну и "на закуску".
Ещё есть слово WORDWORKER2+.
Оно умеет работать с двумя фиксированными "параметрами справа".
И одним опциональным. Предварённым другим ключевым словом.
Вот пример:
WORDWORKER2+ если // - "если" - ОСНОВНОЕ ключевое слово. С которого начинается разбор грамматики иначе // - "иначе" - ДОПОЛНИТЕЛЬНОЕ ключевое слово. Которого может и не быть. WordToWork1 DO // - вычислили значение "первого аргумента справа" IF ( WordToWork2 DO // - выполняем "второй аргумент справа" ) ELSE ( WordToWork2+ DO // - выполняем третий опциональный аргумент справа, если он передан" // Если же он НЕ ПЕРЕДАН, то нам в аргументе WordToWork2+ - передадут уже знакомое слово NOP ) END // если
Тогда можно написать так:
Если ( "Контрол в фокусе" ЯВЛЯЕТСЯ "Строкой ввода") то ( "Присвоить текст {(aText)} в" "Контрол в фокусе" ) иначе ( false ASSERT ) // - тут просто "упадём".
По-моему - "уже перебор информации".
Поэтому - закругляюсь.
Чуть позже я расскажу - как регистрировать РЕАЛЬНЫЕ классы объектов в тестовой машине, чтобы работать с их идентификаторами, а не со "строковыми именами".
И БОЛЕЕ ТОГО - вызывать их КОНСТРУКТОРЫ. Т.е. на самом деле - скриптовая машина - МОЖЕТ обладать возможностью СОЗДАВАТЬ объекты реального приложения.
Неплохо для "тестовой машины", а?
На самом деле - наверное самые пытливые читатели отметили, для себя, что эту скриптовую машину можно использовать не только для тестирования, но и для АВТОМАТИЗАЦИИ и написания макросов пользователя.
Такой вот VBA (http://ru.wikipedia.org/wiki/VBA) "на коленке".
Если компилировать "скриптовую обвязку" не только под IfDef Test, но и для конечного клиентского приложения.
И ДАТЬ пользователю возможность загружать и выполнять скрипты.
P.S. Я ещё вас не утомил? А то у меня план статей разросся уже до 30-ти штук.
Кому-то вообще интересно "сделать скриптовую машину своими руками" из "модели для сборки"?
Или пора закругляться?
Учитывая, что каждая новая статья приносит с собой ещё две статьи в "план для написания".
Да, это круто всё! :)
ОтветитьУдалитьТолько вот Александр, скажите мне. Правильно ли я понимаю, что у вас такая картина получается: тесты исполняются самим exe-шником?
Ну т.е. проект может собираться в обычном режиме (типа Release) и в режиме для тестирования - в этом режиме подключается код для прогонки скриптов....
Или всё-таки скрипты гоняются внешней программой по отношению к тестируемому проекту?
Да! Тесты гоняются ВНУТРИ exe-шника.
УдалитьЯ же писал. Под IfDef.
Но! НИЧТО не мешает определить АКСИОМАТИКУ внутри exe-шника. А тесты - СНАРУЖИ.
Только - АКСИОМАТИКА - внутри.
> Я же писал
УдалитьНу на всякий случай уточнил.
> Тесты гоняются ВНУТРИ exe-шника
Ну вот в этом и прелесть Вашего подхода :)
"Ну вот в этом и прелесть Вашего подхода" - вы ПЕРВЫЙ человек, который СКАЗАЛ мне об этом. Это - ПРАВДА - ПРЕЛЕСТЬ. Я могу назвать "множество плюсов". Ну или написать статью о них.
УдалитьУ нас даже название есть - InsiderTest'ы.
Удалить