如何使用RestKit正确测试映射(嵌套映射,对多个)

时间:2013-12-05 20:48:51

标签: objective-c unit-testing core-data mapping restkit

我正在尝试测试我的Core Data模型的响应映射。我在Core Data模型中只有几个类,但其中有两个我测试很有趣。第一类是CTFUser类,它保留有关用户的基本信息,第二类是CTFCharacter类。用户可能只有很少的角色(某种类型的玩家)多对多关系。我想要做的是正确编写CTFUser类的测试以及CTFUserCTFCharacter类之间的关系。当我编写没有属性characters的测试时,NSOrderedSet类型测试已通过。当我尝试在不检查characters value次测试通过的RKPropertyMappingTestExpectation的情况下测试属性{ "username": "tomkowz12", "email": "tmk.szlc@gmail.com", "password": "password123", "nick": "black_lord", "location": [10, 20], "characters" : [{ "type": 1, "total_time": 21, "total_score": 100, "health": 100, "level": 20, "is_active": 1 }, { "type": 2, "total_time": 23, "total_score": 98, "health": 55, "level": 12, "is_active": 0 }] } 时。但是当我想检查这个映射的值时,我遇到了崩溃。

测试中使用的JSON夹具:

@interface CTFUser : CustomManagedObject

@property (nonatomic, retain) NSString * email;
@property (nonatomic, retain) NSString * nick;
@property (nonatomic, retain) NSString * username;
@property (nonatomic, retain) NSString * password;
@property (nonatomic, retain) id location;
@property (nonatomic, retain) CTFGame *game;
@property (nonatomic, retain) NSOrderedSet *characters;
+ (NSDictionary *)dictionaryForResponseMapping;

@end

CTFUser类

+ (NSDictionary *)dictionaryForResponseMapping {
return @{@"username" : @"username",
         @"email" : @"email",
         @"password" : @"password",
         @"nick" : @"nick",
         @"location" : @"location"};
}

和包含此类的属性映射的字典字典:

@interface CTFCharacter : CustomManagedObject

@property (nonatomic, retain) NSNumber * type;
@property (nonatomic, retain) NSNumber * totalTime;
@property (nonatomic, retain) NSNumber * totalScore;
@property (nonatomic, retain) NSNumber * health;
@property (nonatomic, retain) NSNumber * level;
@property (nonatomic, retain) NSNumber * active;
@property (nonatomic, retain) CTFUser *user;

+ (NSDictionary *)dictionaryResponseMapping;

@end

CTFCharacter class

+ (NSDictionary *)dictionaryResponseMapping {
    return @{@"type": @"type",
             @"total_time": @"totalTime",
             @"total_score": @"totalScore",
             @"health": @"health",
             @"level": @"level",
             @"is_active": @"active"};
}

带有属性映射的字典:

    /// Configure mapping
    RKEntityMapping *userMapping =
    [RKEntityMapping mappingForEntityForName:NSStringFromClass([CTFUser class]) inManagedObjectStore:_manager.managedObjectStore];
    [userMapping addAttributeMappingsFromDictionary:[CTFUser dictionaryForResponseMapping]];

    RKEntityMapping *characterMapping =
    [RKEntityMapping mappingForEntityForName:NSStringFromClass([CTFCharacter class]) inManagedObjectStore:_manager.managedObjectStore];
    [characterMapping addAttributeMappingsFromDictionary:[CTFCharacter dictionaryResponseMapping]];

    [userMapping addRelationshipMappingWithSourceKeyPath:@"characters" mapping:characterMapping];

    /// Configure expectations
    RKMappingTest *test = [RKMappingTest testForMapping:userMapping sourceObject:parsedJSON destinationObject:nil];
    test.managedObjectContext = _service.managedObjectContext;

    RKPropertyMappingTestExpectation *usernameExpectation =
    [RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"username" destinationKeyPath:@"username" value:@"tomkowz12"];
    [test addExpectation:usernameExpectation];

    RKPropertyMappingTestExpectation *emailExpectation =
    [RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"email" destinationKeyPath:@"email" value:@"tmk.szlc@gmail.com"];
    [test addExpectation:emailExpectation];

    RKPropertyMappingTestExpectation *passwordExpectation =
    [RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"password" destinationKeyPath:@"password" value:@"password123"];
    [test addExpectation:passwordExpectation];

    RKPropertyMappingTestExpectation *nickExpectation =
    [RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"nick" destinationKeyPath:@"nick" value:@"black_lord"];
    [test addExpectation:nickExpectation];

    RKPropertyMappingTestExpectation *locationExpectation =
    [RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"location" destinationKeyPath:@"location" value:@[@(10), @(20)]];
    [test addExpectation:locationExpectation];

    /// Configure expectation objects
    CTFCharacter *firstCharacter = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([CTFCharacter class]) inManagedObjectContext:_service.managedObjectContext];
    firstCharacter.type = @(1);
    firstCharacter.totalTime = @(21);
    firstCharacter.totalScore = @(100);
    firstCharacter.health = @(100);
    firstCharacter.level = @(20);
    firstCharacter.active = @YES;

    CTFCharacter *secondCharacter = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([CTFCharacter class]) inManagedObjectContext:_service.managedObjectContext];
    secondCharacter.type = @(2);
    secondCharacter.totalTime = @(23);
    secondCharacter.totalScore = @(98);
    secondCharacter.health = @(55);
    secondCharacter.level = @(12);
    secondCharacter.active = @NO;

    NSOrderedSet *set = [[NSOrderedSet alloc] initWithArray:@[firstCharacter, secondCharacter]];
    RKPropertyMappingTestExpectation *charactersExpectation =
    [RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"characters" destinationKeyPath:@"characters" value:set]; /// <-- this won't pass
    // [RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"characters" destinationKeyPath:@"characters"]; /// <-- this pass

    [test addExpectation:charactersExpectation];

    [test verify];
}

**单元测试**      - (void)testUserResponseMApping {         id parsedJSON = [RKTestFixture parsedObjectWithContentsOfFixture:@“user-response.json”];

<unknown>:0: error: -[CTFUserTests testUserResponseMApping] : mapped to unexpected _NSFaultingMutableOrderedSet value 'Relationship 'characters' on managed object (0x8c4fba0) <CTFUser: 0x8c4fba0> (entity: CTFUser; id: 0x8c4d2a0 <x-coredata:///CTFUser/t28A63306-B2D2-41F5-A0C3-1BE85520B04710> ; data: {
characters =     (
    "0x8c52470 <x-coredata:///CTFCharacter/t28A63306-B2D2-41F5-A0C3-1BE85520B04711>",
    "0x8c4d330 <x-coredata:///CTFCharacter/t28A63306-B2D2-41F5-A0C3-1BE85520B04712>"
);
email = "tmk.szlc@gmail.com";
game = nil;
location = "(\n    10,\n    20\n)";
nick = "black_lord";
password = password123;
username = tomkowz12;
}) with objects {(
<CTFCharacter: 0x8c528f0> (entity: CTFCharacter; id: 0x8c52470 <x-coredata:///CTFCharacter/t28A63306-B2D2-41F5-A0C3-1BE85520B04711> ; data: {
active = 1;
health = 100;
level = 20;
totalScore = 100;
totalTime = 21;
type = 1;
user = "0x8c4d2a0 <x-coredata:///CTFUser/t28A63306-B2D2-41F5-A0C3-1BE85520B04710>";
}),
<CTFCharacter: 0x8c4ef60> (entity: CTFCharacter; id: 0x8c4d330 <x-coredata:///CTFCharacter/t28A63306-B2D2-41F5-A0C3-1BE85520B04712> ; data: {
active = 0;
health = 55;
level = 12;
totalScore = 98;
totalTime = 23;
type = 2;
user = "0x8c4d2a0 <x-coredata:///CTFUser/t28A63306-B2D2-41F5-A0C3-1BE85520B04710>";
})
)}'
(
0   CoreFoundation                      0x021185e4 __exceptionPreprocess + 180
1   libobjc.A.dylib                     0x01e9b8b6 objc_exception_throw + 44
2   CoreFoundation                      0x021a86a1 -[NSException raise] + 17
3   Capture The FlagTests               0x0a0f1d60 -[RKMappingTest verifyExpectation:] + 464
4   Capture The FlagTests               0x0a0f2054 -[RKMappingTest verify] + 404
5   Capture The FlagTests               0x0a002cf0 -[CTFUserTests testUserResponseMApping] + 3648
6   CoreFoundation                      0x0210cd1d __invoking___ + 29
7   CoreFoundation                      0x0210cc2a -[NSInvocation invoke] + 362
8   XCTest                              0x201032bf -[XCTestCase invokeTest] + 212
9   XCTest                              0x2010338d -[XCTestCase performTest:] + 111
10  XCTest                              0x2010417c -[XCTest run] + 82
11  XCTest                              0x20102a44 -[XCTestSuite performTest:] + 139
12  XCTest                              0x2010417c -[XCTest run] + 82
13  XCTest                              0x20102a44 -[XCTestSuite performTest:] + 139
14  XCTest                              0x2010417c -[XCTest run] + 82
15  XCTest                              0x20102a44 -[XCTestSuite performTest:] + 139
16  XCTest                              0x2010417c -[XCTest run] + 82
17  XCTest                              0x20105aa1 +[XCTestProbe runTests:] + 183
18  Foundation                          0x01ad212c __NSFireDelayedPerform + 372
19  CoreFoundation                      0x020d6bd6 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
20  CoreFoundation                      0x020d65bd __CFRunLoopDoTimer + 1181
21  CoreFoundation                      0x020be628 __CFRunLoopRun + 1816
22  CoreFoundation                      0x020bdac3 CFRunLoopRunSpecific + 467
23  CoreFoundation                      0x020bd8db CFRunLoopRunInMode + 123
24  GraphicsServices                    0x03ade9e2 GSEventRunModal + 192
25  GraphicsServices                    0x03ade809 GSEventRun + 104
26  UIKit                               0x00c09d3b UIApplicationMain + 1225
27  Capture The Flag                    0x00008d0d main + 141
28  libdyld.dylib                       0x0275670d start + 1
)

崩溃日志

characters

我犯了错误?应该如何测试- (void)getUser { CoreDataService *_service = [CoreDataService sharedInstance]; RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:_service.managedObjectModel]; _connection.manager.managedObjectStore = managedObjectStore; RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([CTFUser class]) inManagedObjectStore:managedObjectStore]; [userMapping addAttributeMappingsFromDictionary:[CTFUser dictionaryForResponseMapping]]; RKEntityMapping *characterMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([CTFCharacter class]) inManagedObjectStore:managedObjectStore]; [characterMapping addAttributeMappingsFromDictionary:[CTFCharacter dictionaryResponseMapping]]; [userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"characters" toKeyPath:@"characters" withMapping:characterMapping]]; RKResponseDescriptor *descriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping method:RKRequestMethodGET pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]; [_connection.manager addResponseDescriptor:descriptor]; [_connection.manager getObject:nil path:@"test" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { CTFUser *fetchedUser = (CTFUser *)mappingResult.firstObject; NSLog(@"%@", fetchedUser); } failure:^(RKObjectRequestOperation *operation, NSError *error) { NSLog(@"failure"); }]; } 属性的值?其他值正在测试中并通过。

编辑:

当我发出请求时,来自服务器的响应看起来很好,所有属性和关系都已正确映射,但仍然会出现测试问题。

{{1}}

提前谢谢。

1 个答案:

答案 0 :(得分:0)

好的,我做到了。解决方法非常简单。昨天已经晚了所以我没有找到RestKit文档。

而不是使用:

expectationWithSourceKeyPath:destinationKeyPath:value:

我用过:

expectationWithSourceKeyPath:destinationKeyPath:evaluationBlock:

更改后的代码如下所示:

RKPropertyMappingTestExpectation *charactersExpectation =
[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"characters" destinationKeyPath:@"characters" evaluationBlock:^BOOL(RKPropertyMappingTestExpectation *expectation, RKPropertyMapping *mapping, id mappedValue, NSError *__autoreleasing *error) {

    NSArray *commitedKeysToCompare = @[@"type, totalTime, totalScore, healt, level, active"];

    NSArray *array = [mappedValue allObjects];
    BOOL containsTwoItems = array.count == 2;

    /// Test First character
    CTFCharacter *firstFetchedCharacter = (CTFCharacter *)array[0];

    CTFCharacter *firstReferenceCharacter = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([CTFCharacter class]) inManagedObjectContext:_service.managedObjectContext];
    firstReferenceCharacter.type = @(1);
    firstReferenceCharacter.totalTime = @(21);
    firstReferenceCharacter.totalScore = @(100);
    firstReferenceCharacter.health = @(100);
    firstReferenceCharacter.level = @(20);
    firstReferenceCharacter.active = @YES;

    BOOL isFirstEqual = [[firstFetchedCharacter committedValuesForKeys:commitedKeysToCompare] isEqual:[firstReferenceCharacter committedValuesForKeys:commitedKeysToCompare]];

    /// Test Second character
    CTFCharacter *secondFetchedCharacter = (CTFCharacter *)array[1];

    CTFCharacter *secondReferenceCharacter = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([CTFCharacter class]) inManagedObjectContext:_service.managedObjectContext];
    secondReferenceCharacter.type = @(2);
    secondReferenceCharacter.totalTime = @(23);
    secondReferenceCharacter.totalScore = @(98);
    secondReferenceCharacter.health = @(55);
    secondReferenceCharacter.level = @(12);
    secondReferenceCharacter.active = @NO;

    BOOL isSecondEqual = [[secondFetchedCharacter committedValuesForKeys:commitedKeysToCompare] isEqual:[secondReferenceCharacter committedValuesForKeys:commitedKeysToCompare]];

    return isFirstEqual && isSecondEqual && containsTwoItems;
}];