我们使用 Perl 进行 GUI 测试自动化。 它非常成功。 我们为 GUI 测试编写了一种非常轻量级的 DSL 语言。 DSL 与对象模型非常相似。
例如,我们在根有一个 Application 对象。 应用程序中的每个属性表都是一个 View 对象。 页面下的每个页面称为Page对象本身。
我们从 Perl 向 GUI 应用程序发送命令,GUI 解释该命令并很好地响应该命令。 要发送命令,我们执行以下操作:
socket_object->send_command("App.View2.Page2.Activate()")
socket_object->send_command("App.View1.Page3.OKBtn.Click()")
这不太可读。 相反,我想为应用程序、视图和页面编写 Perl DSL。
Perl 是否提供了某种 DSL 结构,我可以在其中执行以下操作?
App.View2.Page2.Activate();
App.View1.Page2.Click();
其中 App 应是 Application 类的实例。 我必须在运行时获取 View2 的对象。
这样的东西怎么用呢?
We use Perl for GUI test automation. It has been very successful. We have written a very lightweight DSL kind of language for GUI testing. The DSL is very similar to a object model.
For example, we have an Application object at the root. Each property sheet in the application is a View object. Each page under the page is called Page object itself.
From Perl we send commands to a GUI application and the GUI interpret the command and respond to the command nicely. To send a command we do the following:
socket_object->send_command("App.View2.Page2.Activate()")
socket_object->send_command("App.View1.Page3.OKBtn.Click()")
This is not very readable. Instead, I want to write a Perl DSL for App, View and Page.
Does Perl provide some sort of DSL structure where I can do the following?
App.View2.Page2.Activate();
App.View1.Page2.Click();
Where App shall be an instance of the Application class. I have to get the object of View2 at run time.
How to use such a things?
发布评论
评论(6)
您几乎可以用 Perl 做任何事情。 但是你必须做一些奇怪的事情来让 Perl 使用非 Perl 的语法来执行。
要准确处理您所拥有的内容,您将必须使用许多高级技巧,而这些技巧从定义上来说是不那么可维护的。 你必须:
AUTOLOAD
另一种方法是 源过滤器,我可能会因为提及此功能而投反对票。 因此,我不会向寻求帮助的人推荐这种方法。 但它就在那里。 源过滤器(我已经完成了我的分享)只是您可能认为自己太聪明而不利于自己的领域之一。
不过,如果您对 Perl 作为 DSL“宿主”语言感兴趣,那么 源过滤器并不是完全禁止的。 但是,将其限制为您想要执行的操作,Perl6::Attributes 可能会立即完成您需要的大部分功能。 它将采用
.
并将它们翻译为“->” Perl 会理解的。 但您仍然可以查看源过滤器以了解幕后发生了什么。我也不想离开这个主题而不建议使用 Damian Conway 的 Filter::Simple。
最简单的事情就是放弃“.” 运算符,而只是期望 Perl 外观的代码。
App
可以是一个包或一个子包。 在当前包中定义或导入,返回一个对象,该对象被祝福到带有View2
子包的包中(可能是AUTOLOAD
sub) 返回包的名称或被祝福到包中的引用,它理解Page2
,然后最后的返回将理解Activate
或Click
。 (如果需要,请参阅面向对象教程。)You can do almost anything in Perl. But you have to do some strange stuff to get Perl to perform with syntax that is just not Perl.
To handle exactly what you have there, you would have to a lot of advanced tricks, which are by definition not that maintainable. You would have to:
AUTOLOAD
sAnother way is source filters, I can probably pick up a downvote just for mentioning this capability. So I wouldn't exactly recommend this approach for people who are asking for help. But it's out there. Source filters (and I've done my share) are just one of those areas where you can think you're too clever for your own good.
Still, if you are interested in Perl as a DSL "host" language, then source filters aren't exactly off limits. However, limiting this to just what you show that you want to do, Perl6::Attributes will probably do most of what you would need right off the shelf. It would take the
.
and translate them into the "->" that Perl would understand. But you can still take a look at source filters to understand what's going on behind the scenes.I also don't want to leave this topic without suggesting that a lot of the frustration you could have generating your own source filter (which I advise NOT to do) is eased by using Damian Conway's Filter::Simple.
The simplest thing is to forgo the '.' operator and just instead expect Perl-looking code.
App
would be either a package or a sub. Either defined in the current package or imported which returns an object blessed into a package with aView2
sub (possibly anAUTOLOAD
sub) which returns either the name of a package or a reference blessed into a package, that understandsPage2
, and then finally the return from that would understandActivate
orClick
. (See the OO tutorial, if you need.)我建议您停止尝试做奇怪的“DSL”事情,而只编写 Perl 类来处理您想要管理的对象。 我建议您考虑使用新的 Moose Perl 对象系统来实现此目的,尽管传统的 Perl OO 就可以了。 深入研究 OO 教程的 Perl 文档; 他们都是伟大的。
I recommend you quit trying to do freaky "DSL" stuff and just write Perl classes to handle the objects you want to manage. I recommend you look into using the new Moose Perl object system for this, although traditional Perl OO would be just fine. Dig through the Perl documentation for the OO tutorials; they are great.
perl5 中的方法调用使用
->
而不是.
,因此它看起来像App->View2->Page2->Activate()< /code> 或
$App->View2->Page2->Active()
除非您做了一些非常有趣的事情(例如,源过滤器)。 假设没问题,您可以使用普通的 Perl OO 内容。现在,您需要的下一部分是在运行时创建方法。 这实际上相当简单:
或者,如果您只想在调用方法时创建方法,那么
AUTOLOAD
就是这样做的。 您还可以滥用自动加载来使所有方法调用成功(但要注意具有特殊含义的方法,例如 DESTROY)。这将为您提供语法。 让您的对象生成一个字符串传递给
send_command
应该不会那么困难。另外,我对它不太熟悉,但你可能想看看 Moose 。 它可能有更简单的方法来实现这一点。
Method calls in perl5 use
->
not.
, so it'll look likeApp->View2->Page2->Activate()
or$App->View2->Page2->Active()
unless you do something really interesting (e.g., a source filter). Assuming that's OK, you can use normal Perl OO stuff.Now, the next part of what you need is to create the methods at runtime. This is actually fairly simple:
Alternatively, if you want to create the methods only when they're called, thats what
AUTOLOAD
does. You can also abuse autoload to make all method calls succeed (though watch out for ones with special meanings, like DESTROY).This will get you the syntax. Having your objects generate a string to pass to
send_command
should not be that difficult.Also, I'm not too familiar with it, but you may want to check out Moose. It may have easier ways to accomplish this.
DSL 源过滤器
这是另一种尝试。 Skiphoppy 有一点道理,但再看一遍,我注意到(到目前为止)你并没有问太多那么复杂的问题。 您只想获取每个命令并告诉远程服务器执行该操作。 perl 不需要理解这些命令,而是服务器。
因此,我删除了一些有关源过滤器的警告,并决定向您展示
如何写一个简单的。 再说一次,你所做的事情并不那么复杂,我下面的“过滤”非常简单。
您需要将其保存在 Perl 可以找到的
RemoteAppScript.pm
中。 (如果您需要知道在哪里,请尝试 perl -MData::Dumper -e 'print Dumper( \@INC ), "\n"' 。)然后您可以创建一个包含以下内容的“perl”文件: this:
但是,
没有真正的原因表明您无法读取包含服务器命令的文件。 这会抛出
FILTER
调用。 你的脚本文件中会有这样的内容,你的 perl 文件看起来更像这样:
并像这样调用它:
DSL Source Filter
Here's another attempt. skiphoppy has a point, but on second look, I noticed that (so far) you weren't asking much that was that complex. You just want to take each command and tell the remote server to do it. It's not perl that has to understand the commands, it's the server.
So, I remove some of my warnings about source filters, and decided to show you
how a simple one can be written. Again, what you're doing is not that complex, and my "filtering" below is quite easy.
You would need to save this in
RemoteAppScript.pm
somewhere where your perl can find it. ( tryperl -MData::Dumper -e 'print Dumper( \@INC ), "\n"'
if you need to know where.)Then you can create a "perl" file that has this:
However
There no real reason that you can't read a file that holds server commands. That would throw out the
FILTER
call. You would havein your script file, and your perl file would look more like this:
And call it like so:
http://search.cpan.org/dist/Devel-Declare/ 是现代的源过滤器的替代方案,它可以直接集成到 perl 解析器中,值得一看。
http://search.cpan.org/dist/Devel-Declare/ is modern alternative to source filters which works at integrating directly into perl parser, and is worth a look.
覆盖
'.'
或使用->
语法的替代方法可能是使用包语法 (::),即创建 App::View2 和 App::View2 等包::Page2 当 View2 / Page 2 创建时,将 AUTOLOAD 子添加到委托给 App::View::Page 或 App::View 方法的包中,如下所示:在您的 App/DSL.pm:
中你的脚本:
An alternative to overriding
'.'
or using->
syntax might be using package syntax (::), i.e. creating packages like App::View2 and App::View2::Page2 when View2 / Page 2 get created, adding an AUTOLOAD sub to the package which delegates to an App::View::Page or App::View method, something like this:In your App/DSL.pm:
and in your script: