创建复杂Mock对象层次结构模拟复杂业务场景
- 使用框架辅助创建
- 在Objective - C中,常用的Mock框架有OCMock。以OCMock为例,创建复杂Mock对象层次结构时,首先需要明确业务场景中的对象关系。假设我们有一个电商应用,存在
Order
对象,Order
依赖于User
对象获取用户信息,User
又依赖于UserProfile
对象获取用户详细资料。
- 首先创建顶层Mock对象,比如
Order
的Mock:
id orderMock = [OCMockObject mockForClass:[Order class]];
- 然后为
Order
依赖的User
对象创建Mock,并将其关联到Order
的Mock中。假设Order
有一个方法- (User *)getUser
来获取用户:
id userMock = [OCMockObject mockForClass:[User class]];
[[[orderMock stub] andReturn:userMock] getUser];
- 接着为
User
依赖的UserProfile
对象创建Mock,并关联到User
的Mock中。假设User
有一个方法- (UserProfile *)getUserProfile
:
id userProfileMock = [OCMockObject mockForClass:[UserProfile class]];
[[[userMock stub] andReturn:userProfileMock] getUserProfile];
- 通过这样的层层关联,就构建了一个复杂的Mock对象层次结构,以模拟电商应用中订单获取用户及用户资料的复杂业务场景。
- 定制Mock对象行为
- 对于创建好的Mock对象层次结构,需要根据业务场景定制其行为。比如,
UserProfile
的Mock对象在调用- (NSString *)getUserName
方法时,返回特定的用户名:
[[userProfileMock stub] andReturn:@"MockedUser"] getUserName];
- 对于
Order
的Mock对象,在调用- (BOOL)placeOrder
方法时,可以根据业务逻辑返回特定的结果,例如当用户资料完整时可以下单成功:
[[orderMock stub] andReturnValue:OCMOCK_VALUE(YES)] placeOrder];
针对Mock对象使用带来的性能问题和维护成本的优化策略
- 性能问题优化
- 减少不必要的Mock创建:在测试中,只对真正需要隔离的外部依赖创建Mock对象。如果某些依赖在测试环境中可以直接使用真实对象而不影响测试结果,就使用真实对象。例如,一些简单的工具类,其内部逻辑稳定且不依赖复杂外部资源,可以直接在测试中实例化使用,而不是创建Mock。
- 缓存Mock对象:对于在多个测试用例中都需要使用的相同Mock对象,可以进行缓存。比如,定义一个全局的
NSMutableDictionary
来存储已经创建的Mock对象,在每次需要使用时先从字典中查找,如果存在则直接使用,避免重复创建。
static NSMutableDictionary *mockCache;
+ (id)cachedMockForClass:(Class)cls {
if (!mockCache) {
mockCache = [NSMutableDictionary dictionary];
}
id mock = mockCache[NSStringFromClass(cls)];
if (!mock) {
mock = [OCMockObject mockForClass:cls];
mockCache[NSStringFromClass(cls)] = mock;
}
return mock;
}
- 维护成本优化
- 建立Mock对象规范:制定统一的Mock对象命名规范、创建和使用规范。例如,Mock对象命名可以采用原对象类名加“Mock”后缀的方式,如
UserMock
。在创建Mock对象时,统一在测试类的setUp
方法中进行初始化,这样便于管理和维护。
- 与业务代码同步更新:当业务代码中的对象关系或方法发生变化时,及时更新相应的Mock对象。可以在项目的CI/CD流程中加入对测试用例(包括Mock对象相关测试)的检查,确保Mock对象与业务代码的一致性。
- 使用Mock生成工具:一些工具可以根据类的定义自动生成Mock对象的代码框架,减少手动编写Mock对象代码的工作量,降低出错概率。例如,XCTestCase有一定的代码生成能力,利用它可以快速生成基础的Mock对象代码框架,然后在此基础上根据业务需求进行定制。