🤖 🔎 🐛
MSUITest
MSUITest 是一个完全用 Swift 编写的经典 Gherkin 语法 "Given-When-Then",受其启发的库。
它是 XCUITest 的封装,允许您编写易于阅读的测试,而无需浪费时间阅读 Apple 的“文档”。
📚
内容
为什么要使用 MSUITest
UI 测试在项目中的优先级往往较低。它是缓慢且不稳定的测试。显然,我们应该尝试用单元测试尽可能多地覆盖代码。您甚至可能熟悉测试金字塔。
我甚至没有提到 XCUITest 的敌对界面。🤫
那么,为什么有这个库?为什么我们要在 UI 测试上花费精力?好朋友,这是一个好问题。
单元测试有一定的局限性。它只覆盖隔离的组件。我们需要一种方法来测试用户将在我们的 iOS 应用中看到的内容。UI 测试有助于减少繁琐的手动测试和回归测试。
激动吗?那很好,因为……MSUITesting 来拯救了!
它提供了一个干净的接口,允许每个人——甚至不熟悉 Swift 的人——都能阅读和理解流程。我们可以停止浪费时间搜索如何与 XCUITest 作战,专注于真正重要的事情。
需求
- iOS 10.0+
- Xcode 10.2+
- Swift 5+
安装
Cocoapods
MSUITest被分为两个主要部分,以在正确的时刻和正确的位置提供最佳解决方案。您可以在您的 Podfile 中利用此设置
use_frameworks!
target 'YourAppTarget' do
pod 'MSUITest/App'
end
target 'YouUITestTarget' do
inherit! :search_paths
pod 'MSUITest'
end
手动
你是否觉得老式并且不想使用依赖关系管理器进行黑魔法?没关系。您需要以下几个简单的步骤
- 手动下载项目或通过git子模块。
- 将
MSUITest.xcodeproj
嵌入您的工作区。 - 将
MSUITest.framework
添加到您的iOS应用目标的嵌入式二进制文件
和链接框架和库
中。 - 将
MSUITest.framework
添加到UI测试目标的构建阶段
>将二进制文件与库链接
中。
入门
是时候享受乐趣了
注意:我建议您查看示例项目,以查看不同的用例以及如何在不同的场景中使用该库。
设置无障碍标识符
XCUITest需要无障碍标识符以在屏幕中找到UIKit元素。因此,我们的第一步是在我们的UIViewController中设置所有UIKit元素标识符。
final class HomeViewController: UIViewController {
@IBOutlet private var titleLabel: UILabel!
@IBOutlet private var subTitleLabel: UILabel!
@IBOutlet private var loginButton: UIButton!
@IBOutlet private var registrationButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
view.accessibilityIdentifier = "home.mainView"
titleLabel.accessibilityIdentifier = "home.titleLabel"
subTitleLabel.accessibilityIdentifier = "home.subTitleLabel"
loginButton.accessibilityIdentifier = "home.loginButton"
registrationButton.accessibilityIdentifier = "home.registrationButton"
}
}
创建页面对象
MSUITest使用页面对象模式。页面对象是一个辅助类,它提供与特定屏幕交云的功能,比如加载屏幕、点击按钮和搜索标签。
让我们在UI 测试目标中创建一个。
// 1
import MSUITest
import XCTest
final class HomePage {
// 2
typealias Element = String
}
// 3
extension HomePage: PageObjectUIElementProvider, PageObject {
// 4
func uiElement(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElement {
let query = self.query(for: element, in: queryProvider)
return query[element]
}
private func query(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElementQuery {
// 5
switch element {
case "home.mainView":
return queryProvider.otherElements
case "home.titleLabel", "home.subTitle":
return queryProvider.staticTexts
case "home.loginButton", "home.registrationButton":
return queryProvider.buttons
default:
fatalError("not found: \(element)")
}
}
}
// MARK: - Given
extension HomePage {
// 6
func givenPage() -> HomePage {
XCUIApplication().launchTestMode()
// 7
return self
}
}
- 导入所需的框架。
- 将字符串字面量设置为元素。查阅无障碍标识符提供程序(AIP)以获取更好的方法。
- 实现
PageObjectUIElementProvider
和PageObject
协议以继承MSUITest的强大功能。 - 实现将标识符转换为
XCUIElement
的协议方法。 - 创建用于查找元素的查询对象。查阅官方文档以获取完整的列表。
- 加载和启动测试的方法。您可以查阅启动特定视图以获取更好的方法。
- 在方法结束时返回
self
很重要,以允许函数链。您将在稍后看到函数链的形状。
创建测试用例
现在是时候编写实际的测试了。让我们在UI 测试目标中创建一个。
import XCTest
// 1
class HomeTests: XCTestCase {
func test_whenLoadView_seeExpectedElements() {
// 2
HomePage()
.givenPage()
.thenIShouldSee(element: "home.mainView", timeout: 0.3)
.thenIShouldSeeNavigationBar(text: "Home")
.thenIShouldSee(element: "home.titleLabel", text: "Welcome")
.thenIShouldSee(element: "home.subTitle", text: "Please login")
.thenIShouldSee(element: "home.loginButton", text: "Log In")
.thenIShouldSee(element: "home.registrationButton", text: "Register")
}
}
- 创建
XCTestCase
的子类。 - 实例化页面对象,并用“Given-When-Then”方法的函数链享受乐趣。
等等!thenIShouldSee
是从哪里来的?!🤯
哈哈哈PageObject
协议添加了几个方法。您不需要担心实现,因为所有内容都在协议扩展中。
请阅读PageObject
/PageObjectWhen
/PageObjectShould
的代码文档,以获取方法的全列表。
待办事项
- 使用jazzy doc创建静态网站
- 添加CI + Danger
- 添加对UICollectionView的支持
- 修复Carthage构建错误
免责声明
- 我是这个库的唯一维护者。我没有能够测试所有UI情况,并可能存在一些错误。如果您发现任何错误,请随时提交Issue,我会尽快修复。我对该库在生产应用可能引起的问题概不负责。
- 示例应用中的代码并非用于生产。因此,请勿将其作为实际应用架构的参考,它应进行改进。
许可协议
MSUITest采用MIT许可证发布。有关详细信息,请参阅LICENSE。