0

I have two test targets in my project, a logic test (ModelLogicTests) and the application test (MyAppTests). I have one class that I use in both to test that models are properly built from JSON objects.

The test case is as follows:

// My ModelLogicTests.m
@interface MyModelLogicTests : XCTestCase

@property NSManagedObjectContext *context;
@property NSManagedObjectModel *model;
@property NSPersistentStoreCoordinator *store;
@property NSBundle *bundle;

@end

@implementation MyModelLogicTests

- (void)setUp {
    [super setUp];
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    NSArray *bundles = @[ bundle ];
    self.bundle = bundle;

    self.model = [NSManagedObjectModel mergedModelFromBundles:bundles];
    XCTAssertNotNil( self.model, @"Managed Object Model is \'nil.\'" );

    self.store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.model];
    XCTAssertTrue( self.store, @"Persistent Store coordinator did not initialize properly." );

    NSError *storeError = 0;
    NSPersistentStore *tempStore = [self.store addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:&storeError];
    XCTAssertNil( storeError, @"Error: %@", storeError.debugDescription );
    XCTAssertNotNil( tempStore, @"\'tempStore\' should not be \'nil.'" );


    self.context = [[NSManagedObjectContext alloc] init];
    self.context.persistentStoreCoordinator = self.store;
    XCTAssert( self.context, @"NSManagedObjectContext did not initlaize." );
    XCTAssert(
              self.context.persistentStoreCoordinator,
              @"Context's persistent store did was not stored." );
}

- (void)testBuildSimpleModel {
    NSURL *path = [self.bundle URLForResource:@"SimpleModel" withExtension:@"json"];
    XCTAssertTrue(
                  [path isKindOfClass:[NSURL class]],
                  @"\'path\' is actually an instance of \'%@.\'", [path class] );

    NSData *jsonData = [[NSData alloc] initWithContentsOfURL:path];
    XCTAssertTrue( [jsonData isKindOfClass:[NSData class]], @"" );

    NSError *jsonError = 0;
    NSDictionary *json_dict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonError];
    XCTAssertNil( jsonError, @"JSON Error: %@", jsonError.description );
    XCTAssertTrue( [json_dict isKindOfClass:[NSDictionary class]], @"" );
    XCTAssertEqualWithAccuracy(json_dict.count, (NSUInteger)4, 0, @"" );

    MySpot *spot = [MySpot BuildMySpotFromJSON:json_dict context:self.context];
    XCTAssertNotNil( spot, @"" );

    // this is the problem test here when running as an application test
    XCTAssertTrue(
                  [spot isKindOfClass:[MySpot class]],
                  @"Is actually an instance of \'%@.\'",
                  NSStringFromClass([spot class]) );

    NSError *saveError = 0;
    XCTAssertTrue( [self.context save:&saveError], @"Save Error: %@", saveError.debugDescription );

    XCTAssertEqualObjects( spot.name, @"Montreal", @"" );
    XCTAssertEqualWithAccuracy(spot.latitude.floatValue, (CGFloat)45.5, 0.0, @"" );
    XCTAssertEqualWithAccuracy(spot.longitude.floatValue, (CGFloat)-73.566667, 0, @"" );
    XCTAssertEqualWithAccuracy(
                               spot.status.integerValue,
                               (MySpotStatus)MySpotStatusOpen,
                               0,
                               @"Should be \'open.\'" );
}

The issue is this, running a logic, all tests pass as expected. Under the application test, the following test fails:

XCTAssertTrue(
    [spot isKindOfClass:[MySpot class]],
    @"Is actually an instance of \'%@.\'",
    NSStringFromClass([spot class]) );

And the output is:

-[MyModelLogicTests testBuildSimpleModel] : (([spot isKindOfClass:[MySpot class]]) is true) failed - Is actually an instance of 'MySpot.'

I have double checked that all the resource files, model, and source files, have been added to all the necessary targets.

Why would I get a failed test (as above), when spot is clearly an instance of MySpot?

UPDATE:

As suggested, I added:

NSLog( @"Instance class: %p, Class: %p", [spot class] , [MySpot class] )

// logic test output
Instance class: 0x5a178ac, Class: 0x5a178ac

// app test output
Instance class: 0x6fa24, Class: 0x9ead2cc

So the updated question is, why the difference between application tests and logic test?

Mike D
  • 4,938
  • 6
  • 43
  • 99
  • try `NSLog(@"%p %p", [spot class], [MySpot class])` and see what do you get – Bryan Chen May 31 '14 at 01:15
  • @BryanChen Done. Still confused as to why. – Mike D May 31 '14 at 01:23
  • Try [reading this](http://stackoverflow.com/questions/14471213/iskindofclass-behavior). I can't say it'll help, but it sounds damn similar. No one explains why-- but is it because the .h and the erroneously included .m end up making two class instances for the same class when the .m is included in a testing build? – stevesliva May 31 '14 at 03:21
  • Maybe put a symbolic breakpoint on `objc_allocateClassPair` and see if a class with name `MySpot` is created twice. Not sure if it's possible to watch your classes vs. foundation classes, though. – stevesliva May 31 '14 at 03:28
  • @stevesliva The links listed in that question actually answered mine. Thanks. – Mike D May 31 '14 at 03:39
  • possible duplicate of [isKindOfClass: returns false negative in unit test bundle](http://stackoverflow.com/questions/5755289/iskindofclass-returns-false-negative-in-unit-test-bundle) – Mike D May 31 '14 at 03:39
  • I just wonder if it's a bug with a build tool. Shouldn't happen! – stevesliva May 31 '14 at 03:41
  • @stevesliva Not if it could be classified as bug, since application tests are dependent on the application itself. – Mike D May 31 '14 at 03:42

0 Answers0