如果你不能触摸到它,那么是 Hammer 时刻的到来!
Hammer 是一个触摸、触控笔和键盘合成库,用于模拟用户交互事件。它可以通过在单元测试中触发 UI 动作来提供更佳的方式,尽可能多地模拟真实世界环境。
Hammer 需要 Swift 5.3 和 iOS 11.0 或更高版本。
使用 SwiftPM
.package(url: "https://github.com/lyft/Hammer.git", from: "0.13.0")
使用 CocoaPods
pod 'HammerTests', '~> 0.13.1'
Hammer 单元测试需要在一个宿主应用中运行才能生成触摸。要配置此,请在侧边栏中选择项目,选择您的测试目标,并在常规选项卡中选择一个宿主应用。宿主应用可以是您的主要应用或空包装器,如 TestHost。
SwiftPM 目前不支持创建应用程序。要使用带有 SwiftPM 框架的 Hammer,您需要创建一个 xcodeproj 并设置一个宿主应用。
Hammer 允许您模拟手指、触控笔和键盘事件。同时,它还提供了各种便利方法来模拟更高级的用户交互。
要向视图发送事件,您必须首先创建一个 EventGenerator
// Initialize for an existing UIWindow, ensure that the window is key and visible.
let eventGenerator = EventGenerator(window: myWindow)
// Initialize for a UIView, automatically wrapping it in a temporary window.
let eventGenerator = EventGenerator(view: myView)
// Initialize for a UIViewController, automatically wrapping it in a temporary window.
let eventGenerator = EventGenerator(viewController: myViewController)
在模拟手指或触控笔触摸时,有几种方式可以指定触摸位置
- 默认:如果您未指定位置,它将默认使用屏幕中心。
- 点:一个 CGPoint 在屏幕坐标中。
- 视图:对一个 UIView 或 UIViewController 的引用,位置将是视图可见部分中心。
- 标识符:一个视图的辅助功能标识符字符串,位置将是视图可见部分中心。
默认情况下,Hammer 将显示模拟触摸在视图上。您可以更改此行为以适用于您的事件生成器。
eventGenerator.showTouches = false
手指是 iOS 上最常用的用户交互方法。Hammer 支持同时处理屏幕上多个手指,最多可达到设备上的限制。您可以选择要使用的手指索引,如果未指定,则将自动选择最合适的一个。
基本事件是用户交互的基本构建块,可以将它们组合在一起以创建完整的手势。某些方法允许您指定一个持续时间,并在该时间期间插值变化。
try eventGenerator.fingerDown(at: CGPoint(x: 10, y: 10))
try eventGenerator.fingerMove(to: CGPoint(x: 20, y: 10), duration: 0.5)
try eventGenerator.fingerUp()
为了方便起见,Hammer 提供了许多高级手势。如果您未指定位置,它将自动默认为视图中心。
try eventGenerator.fingerTap()
try eventGenerator.fingerDoubleTap()
try eventGenerator.fingerLongPress()
try eventGenerator.twoFingerTap()
还提供了许多高级手势。
try eventGenerator.fingerDrag(from: CGPoint(x: 10, y: 10), to: CGPoint(x: 20, y: 10), duration: 0.5)
try eventGenerator.fingerPinch(fromDistance: 100, toDistance: 50, duration: 0.5)
try eventGenerator.fingerRotate(angle: .pi, duration: 0.5)
当在 iPad 上运行时,触控笔可用。它允许指定额外的属性,如压力、高度和方位。
原始事件与手指类似,是笔交互的基本构建块。
try eventGenerator.stylusDown(at: CGPoint(x: 10, y: 10), azimuth: 0, altitude: 0, pressure: 0.5)
try eventGenerator.stylusMove(to: CGPoint(x: 20, y: 10), duration: 0.5)
try eventGenerator.stylusUp()
Hammer还提供了许多针对笔的高级手势。如果您未指定位置,它将自动默认为视图中心。
try eventGenerator.stylusTap()
try eventGenerator.stylusDoubleTap()
try eventGenerator.stylusLongPress()
键盘方法接受显式的KeyboardKey
对象或一个Character
。字符将被映射到其最近的键盘键,如有需要,必须用shift键修饰符包装它们。这意味着指定小写的"g"字符等同于指定大写的"G",这对于带有符号的键也同样适用。
// Explicit `KeyboardKey`
try eventGenerator.keyDown(.letterA)
try eventGenerator.keyUp(.letterA)
// Automatic `Character` mapping
try eventGenerator.keyDown("a")
try eventGenerator.keyUp("a")
// Convenience key down and up events
try eventGenerator.keyPress(.letterA)
try eventGenerator.keyPress("a")
要输入字符或较长的字符串并获取自动shift包装,您可以使用keyType()
方法。
try eventGenerator.keyType("This will type the string as specified, including symbols!")
当在全屏应用或测试导航时,指定屏幕坐标中的CGPoint可能很困难。为此,Hammer提供了一些便利方法,通过可访问性标识符在层次结构中查找视图。
let myButton = try eventGenerator.viewWithIdentifier("my_button", ofType: UIButton.self)
try eventGenerator.fingerTap(at: myButton)
此方法如果在层次结构中找不到视图,将会抛出错误。如果您在测试导航或屏幕更改,并且需要等待视图出现,您可以在方法中添加超时。这将等待直到层次结构已更新,然后返回视图。
let myButton = try eventGenerator.viewWithIdentifier("my_button", ofType: UIButton.self, timeout: 1)
try eventGenerator.fingerTap(at: myButton)
您还可以直接将可访问性标识符传递给事件方法。
try eventGenerator.fingerDown(at: "my_draggable_object")
try eventGenerator.fingerMove(to: "drop_target", duration: 0.5)
try eventGenerator.fingerUp()
您通常需要等待模拟器在屏幕上完成某些内容的显示,或者等待动画结束。Hammer提供多种方法,等待直到视图在屏幕上可见或控件可点击。
try eventGenerator.waitUntilVisible("my_label", timeout: 1)
try eventGenerator.waitUntilHittable("my_button", timeout: 1)
- 应用程序或窗口尚未准备好交互
请确保您正在运行单元测试的主应用程序中(设置说明)。要交互视图,它必须显示在屏幕上,并且应用程序必须已完成展示。您可以通过在测试中添加延迟并验证您的视图是否显示在屏幕上来测试这一点。
- 视图不在层次结构中 / 无法找到视图
请确保您指定的视图与用于创建EventGenerator
的视图在同一个层次结构中。如果您使用的是访问性标识符,请检查其拼写是否正确。
- 视图不可见
这意味着视图在层次结构中,但当前未显示在屏幕上,因此无法为其生成触摸。请确保视图在可见范围内,没有被其他视图遮挡,没有隐藏,并且透明度大于0.01。
- 视图不可点击
这意味着视图在层次结构中并且可见于屏幕,但当前无法接收触摸。请确保该视图在中心坐标响应触摸测试,并且启用了用户交互。
Hammer采用Apache许可证发布。请参阅LICENSE