Xcode单元测试中如何比较两个AppResponse对象数组?
问题原因
你用XCTAssertEqual或Nimble的equal断言比较数组时,底层会逐个校验数组内的对象是否相等。但AppResponse继承自NSObject,默认的相等判断逻辑是对比对象的内存地址(NSObject的isEqual:方法默认只看指针是否相同)。
你测试代码里的expectedArray和responsesArray里的AppResponse是两个完全独立的实例,内存地址不一样(错误信息里的0x600003288240和0x6000032948d0就是两个不同的内存地址),所以断言必然失败。
解决方法
要实现对象内容层面的相等对比,必须给AppResponse重写isEqual:和hash方法(这两个方法必须成对重写,符合NSObject的设计约定)。
1. 给AppResponse添加相等判断逻辑
在AppResponse.m文件里补全以下代码:
@implementation AppResponse - (BOOL)isEqual:(id)object { // 同一对象直接返回相等 if (self == object) return YES; // 类型不匹配直接不相等 if (![object isKindOfClass:[AppResponse class]]) return NO; AppResponse *other = (AppResponse *)object; // 逐个对比所有属性值 BOOL stateMatch = (self.state == other.state); BOOL errorCodeMatch = (self.errorCode == other.errorCode); BOOL errorMatch = (self.error == other.error) || [self.error isEqual:other.error]; BOOL responseMatch = (self.response == other.response) || [self.response isEqual:other.response]; return stateMatch && errorCodeMatch && errorMatch && responseMatch; } - (NSUInteger)hash { // 组合所有属性的哈希值,这里用异或简单实现(复杂场景可以用移位相加等方式优化) NSUInteger hashValue = self.state; hashValue ^= self.errorCode; hashValue ^= self.error.hash; hashValue ^= self.response.hash; return hashValue; } @end
2. 复用原有断言逻辑
重写完成后,原来的XCTAssertEqual或者Nimble的expect(self.responsesArray).to(equal(expectedArray))就能正常工作了,现在断言会对比对象的内容而非内存地址。
临时替代方案(无需修改模型代码)
如果不想改动AppResponse的源码,可以在测试代码里手动逐个校验对象的属性:
// 先校验数组长度一致 XCTAssertEqual(self.responsesArray.count, expectedArray.count) // 遍历逐个对比属性 for (idx, expectedItem) in expectedArray.enumerated() { let actualItem = self.responsesArray[idx] XCTAssertEqual(actualItem.state, expectedItem.state) XCTAssertEqual(actualItem.errorCode, expectedItem.errorCode) XCTAssertEqual(actualItem.error, expectedItem.error) XCTAssertEqual(actualItem.response, expectedItem.response) }
这种方式适合临时测试,但从长远来看,给模型类重写isEqual:和hash是更规范的做法,能在所有需要对比对象内容的场景复用。
内容的提问来源于stack exchange,提问作者YosiFZ
相关产品推荐
相关产品推荐

