开发者

Error Building Core Data Stack in Unit Tests

I am trying to get started with unit testing an app that uses Core Data. In the setUp method of my unit first test, I can get the path to my data model but for some reason cannot convert it to a NSURL.

My setUp method is:

- (void)setUp {

    NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.testcompany.LogicTests"];
    STAssertNotNil(bundle, @"Error finding bundle to create Core Data stack.");

    NSString *path = [bundle pathForResource:@"DataModel" ofType:@"momd"];
    STAssertNotNil(path, @"The path to the resource cannot be nil.");

    NSURL *modelURL = [NSURL URLWithString:path];开发者_如何学Go
    STAssertNotNil(modelURL, @"The URL to the resource cannot be nil. (tried to use path:%@, modelURL is %@)", path, modelURL);

    ...

}

The error I'm getting is:

/Users/neall/iPhone Apps/TestApp/UnitLogicTests.m:24:0 "((modelURL) != nil)" should be true. The URL to the resource cannot be nil. (tried to use path:/Users/neall/iPhone Apps/TestApp/build/Debug-iphonesimulator/LogicTests.octest/DataModel.momd, modelURL is (null))

I've checked the filesystem and the directory /Users/neall/iPhone Apps/TestApp/build/Debug-iphonesimulator/LogicTests.octest/DataModel.momd exists.

What am I missing here?

Thanks!


Try using [NSURL fileURLWithPath:path] instead to construct the url


Double check that you are seeing a directory called DataModel.momd at /Users/neall/iPhone Apps/TestApp/build/Debug-iphonesimulator/LogicTests.octest/DataModel.momd.

If you added a xcdatamodel file by the Add New File... command in Xcode, you would only have one file and it would be DataModel.mom (no trailing d). If that's the case, changing the

NSString *path = [bundle pathForResource:@"DataModel" ofType:@"momd"];

to

NSString *path = [bundle pathForResource:@"DataModel" ofType:@"mom"];

will fix your immediate issue.

You want to use the fileURLWithPath: that Claus suggested as well.

If you want to do versioning of your model in the future and you currently have only a .mom file, select your DataModel.xcdatamodel file in XCode and go to Design -> Data Model -> Add Model Version. This will force the creation of the DataModel.momd directory with the DataModel.mom file in it. You can just delete the new version it adds into that directory and your original tests will work.


xcdatamodel should also be added to Project -> Targets -> "unit test target" -> build phases -> compile sources


After spending several hours stacking in July 2014 this post was one of several that in part led me to the working solution. We somehow managed to break the surprisingly fragile (and mysterious) mechanism that links the bundle that your source code lives in to the bundle that runs the unit test. Further you might have a misnamed xcdatamodel. See comments for explanations:

-(NSManagedObjectContext *) getManagedObjectContext
{
   NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
   //Replace MyClass with class that is from your data model
   //really any of your classes should work
   NSBundle * bundle = [NSBundle bundleForClass:[MyClass class]];

   //You can uses this line to figure you what your bundle is actually named
   //In my case the because my PRODUCT_NAME had spaces in it they was replaced with '-' 
   //(dashes) and I couldn't divine it from the info.plist and the Build Settings.
   NSString * ident =[bundle bundleIdentifier];


   //This will show you where your app is actually out building temporary files
   //The exact location appears to change every version or to of Xcode so
   //this is useful for figuring out what your model is named
   NSString * bundlePath =[bundle bundlePath];


   //Here replace Name_of_model_without_the_dot_xcdatamodel with the name of your 
   //xcdatamodel file without an extension
   //Some tutorials will have you use AppName.xcdatamodel others will simply name it
   //DataModel.xcdatamodel.
   //In any event if bothe path and path1 return null then check the 
   //bundlePath by going to Finder and pressing Command-Shift-G and pasting 
   //bundlePath into the pop-up. Look around for a mom or momd file thats the name you want!
   NSString* path = [bundle
              pathForResource:@"Name_of_model_without_the_dot_xcdatamodel"
              ofType:@"momd"];

   //If the above 'path' and 'path1' is not then you want to use this line instead
   NSString* path1 = [bundle
                  pathForResource:@"Name_of_model_without the_dot_xcdatamodel"
                  ofType:@"mom"];

   //the above path lines are simply so you can trace if you have a mom or a momd file
   //replace here appropriately 
   NSURL *modelURL = [bundle URLForResource:@"Name_of_model_without the_dot_xcdatamodel" 
       withExtension:@"momd"];

   //the rest is boiler plate:
   NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

   NSPersistentStoreCoordinator *psc =
      [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];

   [psc addPersistentStoreWithType:NSInMemoryStoreType 
      configuration:nil URL:nil options:nil error:nil];

   [moc setPersistentStoreCoordinator:psc];
   return moc;
}

Here is how you might use the above context:

-(void)testMyStuff
{

   NSManagedObjectContext* context=[self getManagedObjectContext];
   MyClass *myobj=[NSEntityDescription insertNewObjectForEntityForName:@"MyClass"   
   inManagedObjectContext:context];
}

One final note you may also have to add your source files and xcmodel under the "Compile Sources" of build phases. This unfortunately changes with almost every version of Xcode. For Xcode 5:

Error Building Core Data Stack in Unit Tests

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜