iOS 测试 SwiftMonkey :iOS 上的 monkey

恒温 · 2017年02月18日 · 最后由 ruoyu.wang 回复于 2018年09月26日 · 9554 次阅读
本帖已被设为精华帖!

从前有种测试叫瞎点测试,哦不,随机测试。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 将本帖设为了精华贴 02月18日 19:32

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

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

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

恒温 #52 · 2017年02月19日 Author

#4 楼 @gogle 嗯,是

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

匿名 #7 · 2017年02月20日

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

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

正好可以实践下

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

匿名 #11 · 2017年02月20日

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

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

恒温 #13 · 2017年02月20日 Author

#8 楼 @app_test
#12 楼 @sixleaves

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

认真看完文章,好吗?

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

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

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

恒温 #15 · 2017年02月20日 Author

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

恒温 #16 · 2017年02月21日 Author

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

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

恒温 #18 · 2017年02月23日 Author
重来看雨 回复

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

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

恒温 #37 · 2017年02月23日 Author
bauul 回复

Appium 效率有点慢

恒温 回复

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

恒温 #22 · 2017年02月23日 Author
bauul 回复

Swift monkey 就是 XCTest

恒温 回复

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

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

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

看来 ios 也要学起来了。。

匿名 #30 · 2017年03月24日

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

恒温 #27 · 2017年03月24日 Author

没有引入成功吧?

匿名 #28 · 2017年03月24日
恒温 回复

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

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

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

匿名 #25 · 2017年03月27日

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

恒温 #33 · 2017年03月27日 Author

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

匿名 #23 · 2017年03月27日
恒温 回复

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

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

匿名 #36 · 2017年03月30日
feng 回复

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

好的,谢谢

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

恒温 #39 · 2017年04月17日 Author
小施 回复

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


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

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

12楼 已删除

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

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

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

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

命令行启动 可以用 xcodebuild

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

52楼 已删除

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

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

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

xcode9 貌似不行呀

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册