I have a small data object that needs to be serialized and deserialized. Lets say it is called WeatherDetails
, and it looks like this:
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"];
}
Currently my tests look like this;
#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]);
}
I have a gut feeling that this approach to testing if all properties are correctly encoded is not really optimal as there is duplication, but I can't really think of a better approach. Does anyone have a tip for me on improving this?
What you really want to test is that the object is same before and after you archive it.
Implement a method in your WeatherDetails
to compare the objects (or override isEqual:
).
- (BOOL)isEqualToWeatherDetails:(WeatherDetails *)details
{
if (![details isKindOfClass:[WeatherDetails class]]) return NO;
return [self.weatherCode == details.weatherCode && self.weatherDescription isEqualToString:details.weatherDescription];
}
Then you can do all your equality comparisons at once:
- (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]);
}
If you overrode isEqual:
then you could compare doing this:
XCTAssertEqualObjects(details, unarchive);
Apple tends to add additional methods (isEqualToArray:
, isEqualToDictionary:
). isEqual:
is used by collections like NSSet and NSDictionary
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With