Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 第7章:测试 MVVM 应用

第7章:测试 MVVM 应用

Mock 数据与依赖注入

1. Mock 数据的作用与实现

在 MVVM 架构中,Mock 数据是测试 ViewModel 和 Model 逻辑的关键工具,它能够:

  • 隔离依赖:避免测试受网络、数据库等外部服务影响。
  • 提高测试速度:使用本地模拟数据替代耗时操作。
  • 覆盖边界条件:模拟异常场景(如网络错误、空数据)。

实现方式(Swift 示例):

// 定义协议抽象网络服务  
protocol TodoServiceProtocol {  
    func fetchTodos() async throws -> [Todo]  
}  

// 生产环境实现  
class TodoService: TodoServiceProtocol {  
    func fetchTodos() async throws -> [Todo] {  
        // 实际网络请求代码  
    }  
}  

// Mock 实现  
class MockTodoService: TodoServiceProtocol {  
    var mockTodos: [Todo] = []  
    var shouldFail = false  

    func fetchTodos() async throws -> [Todo] {  
        if shouldFail {  
            throw NetworkError.requestFailed  
        }  
        return mockTodos  
    }  
}  

2. 依赖注入(DI)在 MVVM 中的应用

依赖注入通过解耦组件依赖关系,使测试和维护更灵活。

常见模式:

  1. 构造函数注入(推荐):

    class TodoViewModel {  
        private let service: TodoServiceProtocol  
    
        init(service: TodoServiceProtocol = TodoService()) {  
            self.service = service  
        }  
    }  
    
    // 测试时注入 Mock  
    let mockService = MockTodoService()  
    let viewModel = TodoViewModel(service: mockService)  
    
  2. 属性注入:

    class TodoViewModel {  
        var service: TodoServiceProtocol = TodoService()  
    }  
    

3. 结合 XCTest 的测试案例

class TodoViewModelTests: XCTestCase {  
    func testFetchTodosSuccess() async {  
        // 1. 准备 Mock  
        let mockService = MockTodoService()  
        mockService.mockTodos = [Todo(id: 1, title: "Test")]  

        // 2. 注入依赖  
        let viewModel = TodoViewModel(service: mockService)  

        // 3. 执行测试  
        await viewModel.loadTodos()  

        // 4. 验证结果  
        XCTAssertEqual(viewModel.todos.count, 1)  
    }  
}  

4. 最佳实践

  • 协议抽象:为所有外部服务定义协议。
  • 默认参数:生产代码使用默认实现,测试时覆盖。
  • 集中管理:使用依赖容器(如 Swinject)管理复杂依赖。

案例扩展:在 Todo 应用中,可以通过 Mock 数据测试“空列表提示”或“网络错误弹窗”等 UI 逻辑,而无需真实触发 API。

Last Updated:: 4/25/25, 8:19 PM