Question

I'm using RestKit ~> 0.20.3 and RestKit/Testing ~> 0.20.3. So this is an example of my mapping:

RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[PlayerVO class]];
[mapping addAttributeMappingsFromArray:@[@"firstName", @"middeName", @"lastName", @"dob", @"sex"]];

This is my mock data:

NSDictionary *data = @{@"players": @[@{@"firstName": @"Ahmed", @"middleName": @"Ahmed", @"lastName": @"Ahmed", @"dob": @"100", @"sex": @"m"}]};

This is my mappingTest:

RKMappingTest *mappingTest = [RKMappingTest testForMapping:mapping sourceObject:data destinationObject:nil];

And finally my expectation:

RKPropertyMappingTestExpectation *expectation = [RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"players.firstName" destinationKeyPath:@"firstName" evaluationBlock:^BOOL(RKPropertyMappingTestExpectation *expectation, RKPropertyMapping *mapping, id mappedValue, NSError *__autoreleasing *error) {
    BOOL expect = [mappedValue length] > 0;

    XCTAssertTrue(expect);

    return expect;
}];

[mappingTest addExpectation:expectation];

XCTAssertTrue([mappingTest evaluate]);
XCTAssertNoThrow([mappingTest verify]);

So this test fails as there doesn't seem to be a way I can specify a key path to follow as the data is an array. This is the error I get:

testPlayerServiceGetPlayers] : (([mappingTest verify]) does not throw) failed: throwing "0x8e7d770: failed with error: (null)
RKMappingTest Expectations: (
    "map 'players.firstName' to 'firstName' satisfying evaluation block"
)
Events: (
) during mapping from {
    players =     (
                {
            dob = 100;
            firstName = Ahmed;
            lastName = Ahmed;
            middleName = Ahmed;
            sex = m;
        }
    );
} to (null) with mapping <RKObjectMapping:0x8e6aad0 objectClass=PlayerVO propertyMappings=(
    "<RKAttributeMapping: 0x8e6b880 firstName => firstName>",
    "<RKAttributeMapping: 0x8e61df0 middeName => middeName>",
    "<RKAttributeMapping: 0x8e2f580 lastName => lastName>",
    "<RKAttributeMapping: 0x8e67a60 dob => dob>",
    "<RKAttributeMapping: 0x8e2c120 sex => sex>"
)>"

If I change my data to:

NSDictionary *data = @{@"firstName": @"Ahmed", @"middleName": @"Naseer", @"lastName": @"Nuaman", @"dob": @"524534400", @"sex": @"m"};

And the expectation's expectationWithSourceKeyPath to @"firstName", the tests pass. So this leads me to believe the issue is clearly relative to setting the key path. Now in my app that's done using:

RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:nil keyPath:@"players" statusCodes:statusCodes];

However I can't find a way of setting the keyPath for a RKMappingTest or RKPropertyMappingTestExpectation, any ideas on how I can achieve this?

Update

So I had a look throughRKMappingTest.h and found the rootKeyPath. I set the following:

mappingTest.rootKeyPath = @"players";

And still was having problems regarding the mappedValue in the RKPropertyMappingTestExpectation. So I also changed my data to this:

NSDictionary *data = @{@"players": @{@"firstName": @"Ahmed", @"middleName": @"Ahmed", @"lastName": @"Ahmed", @"dob": @"100", @"sex": @"m"}};

And now I can see that mappedValue is now set to Ahmed and updated the RKPropertyMappingTestExpectation to the following:

RKPropertyMappingTestExpectation *expectation = [RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"firstName" destinationKeyPath:@"firstName" evaluationBlock:^BOOL(RKPropertyMappingTestExpectation *expectation, RKPropertyMapping *mapping, id mappedValue, NSError *__autoreleasing *error) {
    return [mappedValue isEqualToString:@"Ahmed"];
}];

But this is using an object rather than an array. Any more suggestions?

Était-ce utile?

La solution 2

You're thinking about testing, and more specifically the scope of testing, wrongly. This is a unit test, and the unit is the mapping. The mapping deals with individual items and that is why your modified test works - because the scope is correct.

Response descriptors have a different scope. You can't test the scope of a response descriptor in a mapping test.

Autres conseils

I think I've found a somewhat better answer than the reply "you're testing wrong". You should be able to test properly by wrapping your mapping under test in another mapping.

// Data (in your case, you've used a hard coded string here)
id fixtureData = [RKTestFixture parsedObjectWithContentsOfFixture:@"fixture.json"];

// Setup
RKObjectMapping* wrapperMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
RKObjectMapping *mappingToTest = [RKObjectMapping mappingForClass:[PlayerVO class]];
[mappingToTest addAttributeMappingsFromArray:@[@"firstName", @"middeName", @"lastName", @"dob", @"sex"]];
[wrapperMapping addRelationshipMappingWithSourceKeyPath:@"players" mapping:mappingToTest];
RKMappingTest* test = [RKMappingTest testForMapping:wrapperMapping sourceObject:fixtureData destinationObject:nil];

// If you're dealing with a managed object mapping, you'll need these:
// I usually set up a single store in the "+(void)setUp" method and reset it
// on each test in the "-(void)setUp" method. (note one method is class, one
// is instance).
//test.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
//test.mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext cache:[RKFetchRequestManagedObjectCache new]];

// Expectations
[test addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"..." destinationKeyPath:@"..."]];
// Add others as you see fit (these will work for the mappingToTest mapping).

// Evaluate
XCTAssert([test evaluate]);
NSDictionary* result = test.destinationObject;
// You can verify counts on the result and any other objects.
// If you have variables in other structures you want tracked, you can expand
// on the wrapper mapping. i.e. If your data contained a "teamName" at the
// same level as your array of "players", you could add a mapping from
// "teamName" to an arbitrary keyPath for your dictionary then access it in the
// result variable.

This has worked for me. I think it's short sighted to say that you shouldn't test collection mappings. You may have a poorly designed REST API that necessitates this, or a complex interaction between managed objects that you want to verify is set up correctly when mapping takes place.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top