iOS 测试 SwiftMonkey :iOS 上的 monkey

恒温 · February 18, 2017 · Last by ruoyu.wang replied at September 26, 2018 · 7193 hits
本帖已被设为精华帖!

从前有种测试叫瞎点测试,哦不,随机测试。Android 上有 Monkey。我们以前用 Monkey 来跑 Android 机顶盒,跑出了一堆非常难解决的 kernel 问题,帮助还是很大的。市场上随便挑个 Android 应用,monkey 能跑个 30 分钟应该算是了不起了。苹果没有给 iOS 提供 Monkey。大概 iOS 应用质量比较好吧。。

好在很多无聊的人研究测试技术,于是就有了很多 iOS 上的 monkey 工具。比如基于 UIAutomation 的 monkey —— https://github.com/jonathanpenn/ui-auto-monkey。通过 copy from stackoverflow 和 copy from github 模式,我们也熟练掌握了 iOS 上的 monkey。不幸的是,iOS 和 Xcode 升级之后,UIAutomation 框架被砍掉了,于是很长时间 iOS 没有 monkey 的说法了。然后无聊的外国人又整了一个基于 XCUITesting 框架的 monkey 工具 —— https://github.com/zalando/SwiftMonkey。社区里早就有人用过了,但是都藏着掖着。那我是最近才知道,所以拿过来用用。

安装配置

现在每天都有人来问我 Appium 的问题,90%是安装配置问题,10%是不知所谓。所以想对所有创造自动化工具的人说,你解决了安装配置问题,你就已经成功了。

SwiftMonkey 的配置挺简单的。用 CocoaPods —— 这个我没试过:

target "App" do
pod "SwiftMonkeyPaws", "~> 1.0"
end

target "Tests" do
pod "SwiftMonkey", "~> 1.0"
end

手动安装

https://github.com/zalando/SwiftMonkey 下载下来。把 SwiftMonkey 和 SwiftMonkeyPaws 目录粘贴到你的项目目录下去。然后把他们两的 xcodeproj 拖到项目中去。

然后呢,把 SwiftMonkey.framework 添加为你的 test target 的依赖。在 test 的 build phase 那里添加 Copy Files。如图:

然后其实就可以用了。

对于 SwiftMonkeyPaws,这个玩意就是让你的事件会有一个熊掌的反馈,这个得放到 app 的 target 里去,因为是 app 使用的。放到 Embedded Binaries 即可,如图:

然后在你应用里任何地方导入 SwiftMonkeyPaws,初始化它就可以了。

import SwiftMonkeyPaws

var paws: MonkeyPaws?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if CommandLine.arguments.contains("--MonkeyPaws") {
paws = MonkeyPaws(view: window!)
}
return true
}

SwiftMonkeyPaws的效果就是那些熊掌,如下图:

遇到的坑

  1. 原来是 objc 的代码能否使用?

    1. 可以,只要新建一个 XCUITesting 的新项目即可。如图:

    然后在,在测试用例里加入代码:

    //
    // SwiftMonkeyExampleUITests.swift
    // SwiftMonkeyExampleUITests
    //
    // Created by Dag Agren on 07/11/2016.
    // Copyright © 2016 Zalando SE. All rights reserved.
    //

    import XCTest
    import SwiftMonkey

    class SwiftMonkeyExampleUITests: XCTestCase {

    override func setUp() {
    super.setUp()
    XCUIApplication().launch()
    }

    override func tearDown() {
    super.tearDown()
    }

    func testMonkey() {
    let application = XCUIApplication()

    // Workaround for bug in Xcode 7.3. Snapshots are not properly updated
    // when you initially call app.frame, resulting in a zero-sized rect.
    // Doing a random query seems to update everything properly.
    // TODO: Remove this when the Xcode bug is fixed!
    _ = application.descendants(matching: .any).element(boundBy: 0).frame

    // Initialise the monkey tester with the current device
    // frame. Giving an explicit seed will make it generate
    // the same sequence of events on each run, and leaving it
    // out will generate a new sequence on each run.
    let monkey = Monkey(frame: application.frame)
    //let monkey = Monkey(seed: 123, frame: application.frame)

    // Add actions for the monkey to perform. We just use a
    // default set of actions for this, which is usually enough.
    // Use either one of these but maybe not both.
    // XCTest private actions seem to work better at the moment.
    // UIAutomation actions seem to work only on the simulator.
    monkey.addDefaultXCTestPrivateActions()
    //monkey.addDefaultUIAutomationActions()

    // Occasionally, use the regular XCTest functionality
    // to check if an alert is shown, and click a random
    // button on it.
    monkey.addXCTestTapAlertAction(interval: 100, application: application)

    // Run the monkey test indefinitely.
    monkey.monkeyAround()
    }
    }

    同时,别忘记在 build setting 里勾选上 Swift 的标准库,如图:

    然后运行测试就可以了。

  2. 登录相关:
    这事情其实不难,因为 iOS 的这个 monkey 其实就是你自己写的测试用例嘛。在开始之间用 XCUITesting 搞定登陆的事情就可以了。申明,这个我没试过,我是理论家。

一句话原理

其实你用就可以了,知道原理干嘛呢?人糊涂一点过的好一点。SwiftMonkey 把 XCTesting 的私有 API 拿出来用了,直接通过 XCEventGenerator 来模拟事件。所以如果你的应用植入了 SwiftMonkey 千万不要拿去提交 AppStore。

总结

感谢老外,让我们 copy from stackoverflow 和 copy from github 走的更好。SwiftMonkey 真机和模拟器都可以使用,亲测。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 53 条回复 时间 点赞
026 将本帖设为了精华贴 18 Feb 19:32

等公司发年奖的那天 我就去买1个苹果本然后试验下。。

#2楼 @jiazurongyu 准备换公司了?

这货是随机屏幕坐标操作?

#4楼 @gogle 嗯,是

啊哈哈哈哈哈....多了个理由申请mac或者自带mac了

给力,正好公司的项目能用上。

OC项目可以导入这个swift monkey吗?

正好可以实践下

所以这个swiftMonkey是需要有源码的,跟Android上的Monkey适用范围不一样?

@Lihuazhang 这个monkey测试完后,结果反馈是怎么呈现的?

1.这是侵入式的框架,不像WDA是非侵入式的。这也就限制了它的使用范围,最好是在开发那边使用。
2.测试这边做自动化根本用不上。还有中思路就是用注入的方式,但是又得不偿失。
3.而且又是swift,无法嵌入到OC项目中使用。

恒温 #13 · February 20, 2017 作者

#8楼 @app_test
#12楼 @sixleaves

而且又是swift,无法嵌入到OC项目中使用。
OC项目可以导入这个swift monkey吗?

认真看完文章,好吗?

1.这是侵入式的框架,不像WDA是非侵入式的。这也就限制了它的使用范围,最好是在开发那边使用。
2.测试这边做自动化根本用不上。还有中思路就是用注入的方式,但是又得不偿失。

WDA 一样的思路。而且这种倾入式也不影响发布,使用不同的schema打包即可。

#13楼 @Lihuazhang 哈哈,很高兴和你讨论技术问题啊。QA这边的所谓的侵入式就是必须得嵌入项目,开发层面的侵入式是删除掉这个第三方包还要更改很多代码,依赖太强。所以这边这种侵入式的就必须得和开发配合是吧?你需要项目工程的源代码,这对于我们这边做平台的没多大价值。但不同场景,可能对于你们价值还蛮大的吧~。

恒温 #15 · February 20, 2017 作者

#14楼 @sixleaves 理论上是可以不用源码的。但是签名要动。

恒温 #16 · February 21, 2017 作者

#14楼 @sixleaves 不知道你们做平台的有啥好的解决方案?

如果不需要项目源码就好了。。

恒温 #18 · February 23, 2017 作者
重来看雨 回复

理论上是可以做到不用源码的。

用appium生成随机坐标,随机点击,滑动等事件不就好了?

恒温 #20 · February 23, 2017 作者
bauul 回复

Appium 效率有点慢

恒温 回复

那也可以直接用XCTest来写吧,效率应该会提高些。

恒温 #22 · February 23, 2017 作者
bauul 回复

Swift monkey 就是 XCTest

恒温 回复

“理论上不用源码”,请问这个有没有成功的demo?

这个跳到第三方应用或者到home后 怎么搞

这个monkey,不是跑随机的事件?而是需要自己写用例跑的?

看来ios也要学起来了。。

按照操作弄的,为什么还会报找不到模块,项目是OC写的,我又创建了一个swift的UItests项目

恒温 #28 · March 24, 2017 作者
tester 回复

没有引入成功吧?

恒温 回复

看报错,是没有引入成功,哪里有错误么?

这个感觉是需要项目源码的吧?你楼主写的把 “把 SwiftMonkey 和 SwiftMonkeyPaws 目录粘贴到你的项目目录下去。然后把他们两的 xcodeproj 拖到项目中去。”

这个感觉是需要项目源码的吧?你楼主写的把 “把 SwiftMonkey 和 SwiftMonkeyPaws 目录粘贴到你的项目目录下去。然后把他们两的 xcodeproj 拖到项目中去。”

SwiftMonkey 支持命令行启动么?看GitHub上面提到了,但是没看到命令,而且这个跑出crash后,只能靠crash 文件定位么,还有什么其他的辅助输出么?

恒温 #33 · March 27, 2017 作者
tester 回复

试试看,别舍不得去研究下,自己体验下。

恒温 回复

才解决那个导入报错的问题,现在能跑了,不过都是在xcode上运行的,把SwiftMonkey的文档都看了一遍,也没找到,所以才来问问各位大神,不知道是不是我打开的方式不对,还是就是这样

tester 回复

导入报错怎么解决的呢,我也遇到了

feng 回复

我的是因为目录结构不对,你可以根据样例的目录结构来放

tester 回复

好的,谢谢

一旦却换到桌面,就回不来了,这个有什么办法,回到测试的app吗?

恒温 #39 · April 17, 2017 作者
小施 回复

监控下当前页面,如果不是你要的,重新打开。


真机跑的时候报错了,有大神知道为什么吗?查了很多没查到

summer 回复

解决了,需要把build setting里面的 enable bitcode 设置成no

恒温 回复

监控当前页面有点难吧,因为app的页面不断在变的?

file:///%3Cunknown%3E: test failure: -[SwiftMonkeyExampleUITests testMonkey()] failed: Failure getting snapshot Error Domain=XCTestManagerErrorDomain Code=9 "Error getting main window -25204" UserInfo={NSLocalizedDescription=Error getting main window -25204}

跑的过程中,报了这个错是什么意思?

小施 回复

同问,求大神们解决。@rolex_sky001 亲,你在apptests->MonkeyTests.swift 测试文件里_ = application.descendants(matching: .any).element(boundBy: 0).frame加个断点debug到这一步,然后模拟器里面,手动点右下banana,然后继续run,就可以了。我也刚初学ios,真的是好神奇 when you initially call app.frame, resulting in a zero-sized rect. Doing a random query seems to update everything properly. 注释这样写的,就在这一行fail了,无语,无意中点了下面的banana,就好了,也不知道这又什么关联,大神们看到,帮看一下 xcode 8 + simulator 模拟iphone 6 + ios 10.3

45Floor has been deleted

我的没有触发到随机的事件,不知道哪里有问题,哎

这个要是能支持日志和运行截屏就更强大了

如何设置 运行时长啊 跑了不到一分钟 还没看到点击 就说测试结束了

请问一下,这个monkey支持崩溃之后继续跑的吗?现在好像是遇到crash就停掉了

命令行启动 可以用xcodebuild

另外确实可以不需要源码,参考wda 实现的方式,swiftmonkey实现一个监听的server
xcode执行xcuitestcase时先启一个server,而后再往这个端口发指令,server接受到指令后创建一个session并启动待测app,然后调起monkey

52Floor has been deleted

看了说明,没找到,两次点击间,如何设置延迟

tester 回复

你的命令行可以运行了么?
然后这个是有crash日志输出的吗。我现在是用的模拟器,然后自己记录了运行日志,但是太庞大了

添加了swiftmonkey后,工程中运行app启动就会崩溃。麻烦哪位大神帮忙看下?

xcode9 貌似不行呀

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up