我有一个需要序列化和反序列化的小型数据对象。可以说它被称为WeatherDetails
,它看起来像这样:
WeatherDetails.h
@interface WeatherDetails : NSObject <NSCoding>
{
@private
@protected
}
#pragma mark - Properties
@property (nonatomic, copy) NSString *weatherCode;
@property (nonatomic, copy) NSString *weatherDescription;
@end
WeatherDetails.m
#import "WeatherDetails.h"
@implementation WeatherDetails
NSString *const WEATHER_DETAILS_WEATHER_CODE_KEY = @"s";
NSString *const WEATHER_DETAILS_WEATHER_DESCRIPTION_KEY = @"sT";
#pragma mark - Initialization, NSCoding and Dealloc
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
_weatherCode = [aDecoder decodeObjectForKey:@"weatherCode"];
_weatherDescription = [aDecoder decodeObjectForKey:@"weatherDescription"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_weatherCode forKey:@"weatherCode"];
[aCoder encodeObject:_weatherDescription forKey:@"weatherDescription"];
}
目前我的测试看起来像这样;
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
#import "WeatherDetails.h"
@interface WeatherDetailsTests : XCTestCase
@end
@implementation WeatherDetailsTests
- (void)testThatWeatherCodeIsEncoded
{
WeatherDetails *details = [[WeatherDetails alloc] init];
[details setWeatherCode:@"A"];
NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:details];
WeatherDetails *unarchive = [NSKeyedUnarchiver unarchiveObjectWithData:archive];
XCTAssertEqualObjects(@"A", [unarchive weatherCode]);
}
- (void)testThatWeatherDescriptionIsEncoded
{
WeatherDetails *details = [[WeatherDetails alloc] init];
[details setWeatherDescription:@"A"];
NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:details];
WeatherDetails *unarchive = [NSKeyedUnarchiver unarchiveObjectWithData:archive];
XCTAssertEqualObjects(@"A", [unarchive weatherDescription]);
}
我有一种直觉,即如果所有属性都被正确编码,这种测试方法并不是最佳的,因为存在重复,但我无法想到更好的方法。有没有人对我提出改进的建议?
答案 0 :(得分:3)
您真正想要测试的是在归档之前和之后对象是相同的。
在isEqual:
中实施一种方法来比较对象(或覆盖- (BOOL)isEqualToWeatherDetails:(WeatherDetails *)details
{
if (![details isKindOfClass:[WeatherDetails class]]) return NO;
return [self.weatherCode == details.weatherCode && self.weatherDescription isEqualToString:details.weatherDescription];
}
)。
- (void)testNSCoder
{
WeatherDetails *details = [[WeatherDetails alloc] init];
[details setWeatherCode:@"A"];
details.weatherDescription = @"Cloudy";
NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:details];
WeatherDetails *unarchive = [NSKeyedUnarchiver unarchiveObjectWithData:archive];
XCTAssertTrue([details isEqualToWeatherDetails:unarchive]);
}
然后你可以一次完成所有的平等比较:
isEqual:
如果你覆盖XCTAssertEqualObjects(details, unarchive);
,那么你可以比较这样做:
isEqualToArray:
Apple倾向于添加其他方法(isEqualToDictionary:
,isEqual:
)。 Title
由NSSet和NSDictionary等集合使用
答案 1 :(得分:2)
最后,我通过应用custom assertion;
对其进行了改进何时使用
只要满足以下任何条件,我们就应该考虑创建自定义断言:
- 我们发现自己在测试后的测试中编写(或克隆)相同的断言逻辑
- 我们发现自己在测试的结果验证部分编写了条件测试逻辑。也就是说,我们对Assertion方法的调用嵌入在if语句或循环中。
- 我们测试的结果验证部分遭受了模糊测试,因为我们在测试中使用了程序而不是声明性结果验证。
- 当断言失败时,我们发现自己正在进行频繁调试,因为它们没有提供足够的信息。
自定义断言目前看起来像这样:
/*!
* @define XCTAssertEqualSerialized(value, object, selector)
* Serializes (\a object), then desirializes it and compares result's property (\a propertyName) to (\a value) with XCTAssertEqualObjects
* @param value Value to compare.
* @param object Object to serialize.
* @param selector Objects property to compare.
*/
#define XCTAssertEqualSerialized(value, object, selector) \
({ \
NSData *archived = [NSKeyedArchiver archivedDataWithRootObject:object]; \
NSObject *unarchived = [NSKeyedUnarchiver unarchiveObjectWithData:archived]; \
XCTAssertEqualObjects(value, [unarchived valueForKeyPath:NSStringFromSelector(selector)]); \
})
/*!
* @define XCTAssertNotNilSerialized(object, selector)
* Serializes (\a object), then desirializes it and checks result's property (\a propertyName) is not nil with XCTAssertNotNil
* @param object Object to serialize.
* @param selector Objects property to compare.
*/
#define XCTAssertNotNilSerialized(object, selector) \
({ \
NSData *archived = [NSKeyedArchiver archivedDataWithRootObject:object]; \
NSObject *unarchived = [NSKeyedUnarchiver unarchiveObjectWithData:archived]; \
XCTAssertNotNil([unarchived valueForKeyPath:NSStringFromSelector(selector)]); \
})
这导致测试看起来像这样:
- (void)testThatWeatherCodeIsEncoded
{
WeatherDetails *details = [[WeatherDetails alloc] init];
[details setWeatherCode:@"A"];
XCTAssertEqualSerialized(@"A", details, @selector(weatherCode));
}
- (void)testThatWeatherDescriptionIsEncoded
{
WeatherDetails *details = [[WeatherDetails alloc] init];
[details setWeatherDescription:@"A"];
XCTAssertEqualSerialized(@"A", details, @selector(weatherDescription));
}