因为公司自动化测试框架的一些要求,我们的ruby测试脚本(使用Test Unit)以如下形式组织:
authentication(目录名为feature名字)
- 100_signature.rb (100为测试用例在TestLink对应的ID,后面为简单描述)
- 101_signature_with_invalid_key.rb
在每个测试脚本中,测试类根据ID命名,比如100_xxx.rb中code如下:
1 class TC_100 < Test::Unit::TestCase
2 # …
3 end
这种组织形式给我们的日常执行带来了一些小麻烦,比如想执行一个folder下的所有测试用例,只有采用以下两种方式:
1)写个shell脚本,然后执行完后必须从很长的log中自己手工找出执行状况。
2)维护如下文件管理所有用例:
require 'test/unit/testsuite'
require 'test/unit/ui/console/testrunner'
require 'authentication/100_xxx.rb'
require 'authentication/101_xxx.rb'
class Suites << Test::Unit::TestSuite
def self.suit
suites = self.new('Suites')
suites << TC_100.suite
suites << TC_101.suite
end
end
Test::Unit::UI::Console::TestRunner.run(Suites)
但是这个方法有个问题,必须长期手工维护。比如每次添加新的用例必须手动修改此文件以保持一致。
Ruby语言是强大的,灵活的,我们可以利用元编程的一些基本特性比如eval来轻松解决这个问题。在解决方案2的基础上新代码如下:
require 'test/unit/testsuite'
require 'test/unit/ui/console/testrunner'
path = ARGV[0] # 测试脚本所在的目录
$suite_names = []
Dir.foreach(path) do |filename|
if /d+_/ =~ filename # 我们的命名规范是数字开头,下划线然后是简单描述。
require "#{path}/#{filename}"
testcase_id = filename.split('_')[0]
$suite_names << "TC_#{testcase_id}"
end
end
class Suites << Test::Unit::TestSuite
def self.suit
suites = self.new('Suites')
suite_names.each do |suite_name|
suites << eval("::#{suite_name}.suite") # 这段是关键,利用eval等于动态的插入了一段代码。
end
end
end
Test::Unit::UI::Console::TestRunner.run(Suites)
直接运行"ruby run.rb authentication/"能运行该目录下所有脚本并得到Test-Unit的标准报告。