如何为给定Swift代码编写测试用例,代码不可测时该如何改造?
Swift代码测试适配及用例编写方案
一、现有代码适配测试需要做的修改
原有代码的核心问题是SomeViewModel硬依赖MyFileManager单例,无法替换实现做Mock测试,需要做以下调整:
- 提取协议抽象
MyFileManager的能力,定义文件服务协议,声明需要用到的两个接口 - 为
SomeViewModel增加依赖注入入口,将文件管理实例作为构造参数,默认值保留原单例,不影响原有业务逻辑 - 可选优化:将硬编码的缓存路径提取为可配置常量,方便测试时校验路径正确性
修改后的业务代码如下:
// 新增协议抽象 protocol FileStorageService { func isStored(atPath path: String) -> Bool func readData(atPath path: String) -> Data? } // 让原有MyFileManager实现协议 extension MyFileManager: FileStorageService {} class SomeViewModel { // 把硬编码路径提取为常量 private let cachePath = "xxxxx" // 注入依赖的文件服务 private let fileStorage: FileStorageService // 构造方法默认用原有单例,业务侧代码无需修改 init(fileStorage: FileStorageService = MyFileManager.shared) { self.fileStorage = fileStorage } func getCachedData() -> Data? { if fileStorage.isStored(atPath: cachePath) { return fileStorage.readData(atPath: cachePath) } else { return nil } } }
二、逻辑覆盖测试用例编写
首先实现Mock版本的文件服务,用来模拟不同的返回场景,同时可以校验调用参数是否正确:
class MockFileStorage: FileStorageService { // 模拟文件是否存在的返回值 var isFileExists: Bool = false // 模拟读取到的文件数据 var mockData: Data? // 记录传入的路径,用于校验是否正确 private(set) var receivedPath: String? func isStored(atPath path: String) -> Bool { receivedPath = path return isFileExists } func readData(atPath path: String) -> Data? { receivedPath = path return mockData } }
然后编写测试用例,覆盖所有逻辑分支:
class TestSomeViewModel: XCTestCase { func testGetCachedData() { // 测试用例1:校验缓存路径合法性 let mockStorage = MockFileStorage() let viewModel = SomeViewModel(fileStorage: mockStorage) _ = viewModel.getCachedData() XCTAssertEqual(mockStorage.receivedPath, "xxxxx") // 测试用例2:文件不存在分支,返回nil mockStorage.isFileExists = false let resultWhenNoFile = viewModel.getCachedData() XCTAssertNil(resultWhenNoFile) // 测试用例3:文件存在分支,返回对应模拟数据 let testData = "test cache content".data(using: .utf8) mockStorage.isFileExists = true mockStorage.mockData = testData let resultWhenHasFile = viewModel.getCachedData() XCTAssertEqual(resultWhenHasFile, testData) } }
三个测试点分别覆盖了路径合法性校验、文件不存在分支、文件存在分支,实现完整逻辑覆盖。
内容的提问来源于stack exchange,提问作者emraz
相关产品推荐
相关产品推荐

