在敏捷开发中,经常会听到TDD,BDD这些词语,对于如何进行测试驱动开发,不同的敏捷团队有不同的执行方式,针对于目前在iOS下的测试方案,我们搭建了iOS的自动化测试平台。
需要的安装文件(以下文件放到同一个目录下面,我的命名是setup_cucumber):
1.Frank 源代码 (可以从https://github.com/moredip/Frank下载,该项目用于为本地iOS应用做自动化行为测试)
2.必要的.gem档案 (如果有更新版本的.gem档,可以进行替换)
builder-
3
.
0
.
0
.gem
cucumber-
0
.
10
.
2
.gem
diff-lcs-
1
.
1
.
2
.gem
frank-cucumber-
0
.
6
.
1
.gem
gherkin-
2
.
3
.
7
.gem
json-
1
.
5
.
2
.gem
rack-
1
.
2
.
2
.gem
rspec-
2
.
5
.
0
.gem
rspec-core-
2
.
5
.
2
.gem
rspec-expectations-
2
.
5
.
0
.gem
rspec-mocks-
2
.
5
.
0
.gem
sim_launcher-
0
.
3
.
0
.gem
sinatra-
1
.
2
.
6
.gem
term-ansicolor-
1
.
0
.
5
.gem
tilt-
1
.
3
.gem
|
3.install.sh
#!/bin/sh
sudo gem install *.gem
|
安装很简单,执行install.sh文件就可以了
1.打开Terminal,进入setup_cucumber目录
2.执行 ./install.sh
如果在安装过程出现问题,反复执行几次就可以了。
1.建立一个新的 Target ,命名为 Demo-Frank
2.在项目目录下新建Frank目录,将Frank的源代码复制进来,然后把所有的lib,src 和 resources 添加到Demo-Frank这个Traget
3.添加CFNetwork.framework 到Demo-Frank这个Traget
4.在Demo-Frank这个Traget的"Other Linker Flags"设置项下加入一个flag, "-ObjC"(不要带引号)
5.修改main.m中代码,如下:
#import <UIKit/UIKit.h> #ifdef FRANK #include "FrankServer.h" static FrankServer *sFrankServer; #endif int main(int argc, char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; #ifdef FRANK sFrankServer = [[FrankServer alloc] initWithDefaultBundle]; [sFrankServer startServer]; #endif int retVal = UIApplicationMain(argc, argv, nil, @"YouProjectAppDelegate"); [pool release]; return retVal; }
6.开启accessibility功能。在OSX下,进入System Preferences -> Universal Access,然后选中"Enable access for assistive devices"。在模拟器下,进入Settings -> General -> Accessibility -> Accessibility Inspector 选择"on"。
7.在 Demo-Frank 这个 Target 下进入 Run Script, 在 shell 后面的输入框中键入 /bin/sh, 在 shell 下面的输入框中输入
echo "Copying build to FrankDeploy directory" eche ${BUILD_DIR} ditto "${BUILD_DIR}/Debug-iphonesimulator/YourProject.app" "./FrankDeploy/YourProject_Frank.app"
8.编译运行Demo-Frank,(如果存在通过网络连接获取数据,确保能正常连接,注意防火墙的设定),然后进入你要测试的场景界面。
9.打开浏览器,输入http://localhost:37265,点击右上角的Refresh按钮,当载入完毕后可以看到所有这个界面的elements信息(每次重启Demo-Frank或者要切换测试场景的时候都需要点击Refresh按钮,去获取当前的elements信息)。
如上图所示,当前页面有一个UILabel,它的accessibilityLabel被设置为"UserID:",可以在elements tree西面找到该element。然后在页面最上方"View DOM"的Selector中输入"label marked:'UserID:'",然后点击Flash,在Xcode的输出窗口中可以看到相应的输入信息,如果输入一个不存在的Selector将会弹出提示,告知你当前的元素不存在。
在"Accessibility Elements"当中,会显示当前所有设置有AccessibilityLabel属性element,缩放浏览器和模拟器,让他们能在一个桌面上完全呈现,点击某一个element,看看有什么神奇的效果? 你点中的那个element,在界面上会闪动!
1.在项目目录下新建features目录,该目录用于放置所有需要运行自动化测试的内容。features目录下面新建2个目录step_definitions和support。
2.在support目录下新建一个env.rb文件,其内容如下
require 'frank-cucumber'
3.在step_definitions目录下新建lunch_steps.rb,其内容如下
Given /^I launch the app$/ do # kill the app if it's already running, just in case this helps # reduce simulator flakiness when relaunching the app. Use a timeout of 5 seconds to # prevent us hanging around for ages waiting for the ping to fail if the app isn't running begin Timeout::timeout(5) { press_home_on_simulator if frankly_ping } rescue Timeout::Error end require 'sim_launcher'
app_path = ENV['APP_BUNDLE_PATH'] || app_bundle_path simulator_version = ENV['IOS_SIMULATOR_VERSION'] || "5.0" raise "APP_BUNDLE_PATH was not set. \nPlease set a APP_BUNDLE_PATH ruby constant or environment variable to the path of your compiled Frankified iOS app bundle" if app_path.nil? if( ENV['USE_SIM_LAUNCHER_SERVER'] ) simulator = SimLauncher::Client.for_ipad_app( app_path, simulator_version ) else simulator = SimLauncher::DirectClient.for_ipad_app( app_path, simulator_version ) end num_timeouts = 0 loop do begin simulator.relaunch wait_for_frank_to_come_up break # if we make it this far without an exception then we're good to move on rescue Timeout::Error num_timeouts += 1 puts "Encountered #{num_timeouts} timeouts while launching the app." if num_timeouts > 3 raise "Encountered #{num_timeouts} timeouts in a row while trying to launch the app." end end end # TODO: do some kind of waiting check to see that your initial app UI is ready # e.g. Then "I wait to see the login screen" end
3.在feature目录下新建demo.feature,其内容如下
Scenario: When I lunch the app Then I should see the "UserID:" label
4.在step_definitions目录下新建login.rb,其内容如下
Then /^I should see the "([^"]*)" label$/ do |name| check_element_exists("label marked:'#{name}'") end
5.打开Terminal,进入项目目录,输入cucumber demo.feature,即可进行自动测试,如果有多个feature文件需要进行测试,直接输入cucumber,即可对features目录下的所有feature文件进行测试
写在最后,在自动化测试的过程中,我们需要熟悉Ruby,在feature文件中实际上我们写的就是一些模拟的用户行为,在rb文件中实际上我们写的是针对于这些行为做的解析和动作。过段时间,针对如何写feature和rb会有更加详细的说明。