Swift中的Mock、Stub和Fixture:如何无痛测试

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Swift测试:从理论到实践,使用Mock和Fixture



想象一下,你在烤蛋糕,但面粉用完了。在你去商店买面粉之前,你无法检验奶油是否成功。编写与网络、数据库或复杂依赖项打交道的单元测试的开发者,也有类似的感受。与其等待真实的服务器或数据库,我们使用Swift测试中的Mock对象和Fixture——它们就像是我们的“面粉替代品”,让我们可以随时随地测试隔离的代码片段。



在本文中,我们不会仅仅罗列定义。我们将深入探讨如何在实际中正确应用Swift测试,何时使用Mock,何时使用Stub,以及Fixture如何帮助你在准备数据时保持头脑清醒。开始吧!



什么是Mock、Stub和Fixture?理清概念



在编写代码之前,让我们先统一概念。在iOS单元测试的世界里,Mock和Stub经常被混淆。记住这个简单的规则:



  • Stub(存根)——一个返回预设数据的对象。它不检查如何被调用,只是返回响应。
  • Mock(模拟对象)——一个不仅返回数据,还会检查特定方法是否被调用以及调用参数的对象。它就像一个“间谍”。
  • Fixture(测试夹具)——一组预先准备好的数据(通常是JSON或结构体),用于在测试中创建可预测的环境。


在Swift测试中,我们经常组合使用这些方法。例如,加载一个JSON fixture,解析它,然后将网络层替换为一个Mock,用于检查请求是否发送到了正确的URL。



使用协议编写第一个Swift Mock



在Swift中创建Mock对象最常见的方式是使用协议。在真实项目中,你有一个访问网络的服务。在测试中,你将其替换为Mock。



这是一个抽象的示例:



// 网络层的协议protocol NetworkServiceProtocol {    func fetchUsers(completion: @escaping (Result<[User], Error>) -> Void)}

// 真实实现(访问网络)class RealNetworkService: NetworkServiceProtocol { func fetchUsers(completion: @escaping (Result<[User], Error>) -> Void) { // URLSession, Alamofire 等 }}

// 用于测试的Mockclass MockNetworkService: NetworkServiceProtocol { var fetchUsersCalled = false var resultToReturn: Result<[User], Error> = .success([])

func fetchUsers(completion: @escaping (Result<[User], Error>) -> Void) { fetchUsersCalled = true completion(resultToReturn) }}


现在在测试中,我们可以检查该方法是否被调用:



func testViewModelFetchesUsers() {    let mockService = MockNetworkService()    mockService.resultToReturn = .success([User(id: 1, name: "Test")])

let viewModel = UserViewModel(networkService: mockService) viewModel.loadUsers()

XCTAssertTrue(mockService.fetchUsersCalled, "fetchUsers方法应该被调用")}


注意:我们使用了Swift依赖注入——通过初始化器传递依赖。这是测试的关键模式。



Fixture:如何避免在测试中编写成千上万行代码



当你测试JSON解析或CoreData操作时,你需要真实的数据。但每次在代码中生成它们简直是噩梦。这时Swift测试中的Fixture就派上了用场。



在测试文件夹中创建一个名为users_fixture.json的文件:



[    {"id": 1, "name": "Alice", "email": "alice@example.com"},    {"id": 2, "name": "Bob", "email": "bob@example.com"}]


现在

博客

书籍推荐