Testing mappings of nested JSON arrays

27 views
Skip to first unread message

patrick....@gmail.com

unread,
Dec 31, 2014, 6:13:41 AM12/31/14
to res...@googlegroups.com
Hi,

I need help with testing the mappings of a JSON object with a nested array, like this:
{
   
"items":
   
[
     
{
     
"personId": 4,
     
"firstName": "John",
     
"lastName": "Doe"
     
},
     
{
     
"personId": 5,
     
"firstName": "Mike",
     
"lastName": "Moe"
     
}
   
]
}

In addition, the Person objects that should be mapped are NSManagedObjects:
@interface Person : NSManagedObject
@property (nonatomic, retain) NSNumber * personId;
@property (nonatomic, retain) NSString * firstName;
@property (nonatomic, retain) NSString * lastName;
@end

@implementation Person
@dynamic personId;
@dynamic firstName;
@dynamic lastName;
@end

I set up the mappings like this:
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[NSObject class] rootKeyPath:nil method:RKRequestMethodGET];    
RKEntityMapping *responseMapping = [RKEntityMapping mappingForEntityForName:@"Person" inManagedObjectStore:[RKObjectManager sharedManager].managedObjectStore];
[responseMapping addAttributeMappingsFromArray:@[ @"personId", @"firstName", @"lastName" ]];
responseMapping
.identificationAttributes = @[ @"personId" ];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping method:RKRequestMethodGET pathPattern:@"findpersons" keyPath:@"items" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addRequestDescriptor:requestDescriptor];
[[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];

The API expects an empty GET request and returns a JSON response as shown above. This mapping itself actually works, the Person objects are successfully stored in CoreData.
What does not work, however, is this test for the mapping:
id parsedJSON = [RKTestFixture parsedObjectWithContentsOfFixture:@"Person.json"];
RKEntityMapping *mapping = // ...
Person *person = [[RKObjectManager sharedManager].managedObjectStore.persistentStoreManagedObjectContext insertNewObjectForEntityForName:@"Person"];
NSArray *items = @[ person ];

// Alternatively also tried this with destinationObject person and items
RKMappingTest *test = [RKMappingTest testForMapping:mapping sourceObject:parsedJSON destinationObject:nil];
test
.rootKeyPath = @"items";
test
.managedObjectContext = [RKObjectManager sharedManager].managedObjectStore.persistentStoreManagedObjectContext;

// Alternatively also tried expectationWithSourceKeyPath:destinationKeyPath:evaluationBlock:
// However, it fails before the block is even evaluated.
[test evaluateExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"items.personId" destinationKeyPath:@"personId" value:@4] error:&error];

[test addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"personId" destinationKeyPath:@"personId" value:@4]];
[test addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"firstName" destinationKeyPath:@"firstName" value:@"Max"]];
[test addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"lastName" destinationKeyPath:@"lastName" value:@"Mustertrainer"]];

XCTAssertNoThrow([test verify]);

I stepped into the debugger and found that in RKMappingOperation, Line 760 in method applyAttributeMappings:
id value = (sourceKeyPath == nil) ? [sourceObject valueForKey:@"self"] : [sourceObject valueForKeyPath:sourceKeyPath];
the variable value is an NSArray containing two NSNumber objects, @4 and @5 (both personIds from the JSON object).
Further down the line in method transformValue:toValue:withPropertyMapping:error: the conversion from NSArray to NSNumber obviously fails.
I also found that during the normal execution (not in the unit tests, but in the actual app), the control flow goes through the RKMapp*er*Operation (not RKMapp*ing*Operation).
In mapRepresentationOrRepresentations:atKeyPath:usingMapping: it eventually finds out that the keyPath "items" is a collection of objects and splits it up for the RKMappingOperation to use. Thus the mapping works in the field.

Is there a solution to this problem? Even though mapping JSON arrays is a relatively common use-case, I was unable to find any solutions.

Regards,
Patrick
Reply all
Reply to author
Forward
0 new messages