在单元测试中构建核心数据堆栈时出错
Posted
技术标签:
【中文标题】在单元测试中构建核心数据堆栈时出错【英文标题】:Error Building Core Data Stack in Unit Tests 【发布时间】:2010-07-14 20:00:23 【问题描述】:我正在尝试开始对使用 Core Data 的应用程序进行单元测试。在我的单元首次测试的 setUp 方法中,我可以获得数据模型的路径,但由于某种原因无法将其转换为 NSURL。
我的设置方法是:
- (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];
STAssertNotNil(modelURL, @"The URL to the resource cannot be nil. (tried to use path:%@, modelURL is %@)", path, modelURL);
...
我得到的错误是:
/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))
我已经检查了文件系统并且目录/Users/neall/iPhone Apps/TestApp/build/Debug-iphonesimulator/LogicTests.octest/DataModel.momd
存在。
我在这里错过了什么?
谢谢!
【问题讨论】:
你能在某处上传一个示例项目吗?它应该以这种方式工作。 【参考方案1】:尝试使用[NSURL fileURLWithPath:path]
来构造网址
【讨论】:
【参考方案2】:仔细检查您是否在 /Users/neall/iPhone Apps/TestApp/build/Debug-iphonesimulator/LogicTests.octest/DataModel.momd 看到了一个名为 DataModel.momd 的目录。
如果您在 Xcode 中通过 Add New File... 命令添加了一个 xcdatamodel 文件,您将只有一个文件,它将是 DataModel.mom(没有尾随 d)。如果是这种情况,请更改
NSString *path = [bundle pathForResource:@"DataModel" ofType:@"momd"];
到
NSString *path = [bundle pathForResource:@"DataModel" ofType:@"mom"];
将解决您的直接问题。
您也想使用克劳斯建议的 fileURLWithPath:。
如果你想在未来对你的模型进行版本控制,而你目前只有一个 .mom 文件,请在 XCode 中选择你的 DataModel.xcdatamodel 文件,然后转到设计 -> 数据模型 -> 添加模型版本。这将强制创建包含 DataModel.mom 文件的 DataModel.momd 目录。您只需删除它添加到该目录中的新版本,您的原始测试就可以工作。
【讨论】:
【参考方案3】:xcdatamodel 也应该添加到 项目 -> 目标 -> “单元测试目标” -> 构建阶段 -> 编译源代码
【讨论】:
【参考方案4】:在 2014 年 7 月花了几个小时堆积之后,这篇文章是部分导致我找到工作解决方案的几个帖子之一。 我们以某种方式设法打破了将源代码所在的包链接到运行单元测试的包的异常脆弱(和神秘)的机制。此外,您可能有一个错误命名的 xcdatamodel。解释见 cmets:
-(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;
以下是您可以如何使用上述上下文:
-(void)testMyStuff
NSManagedObjectContext* context=[self getManagedObjectContext];
MyClass *myobj=[NSEntityDescription insertNewObjectForEntityForName:@"MyClass"
inManagedObjectContext:context];
最后一点,您可能还必须在构建阶段的“编译源”下添加源文件和 xcmodel。不幸的是,几乎每个 Xcode 版本都会改变。对于 Xcode 5:
【讨论】:
以上是关于在单元测试中构建核心数据堆栈时出错的主要内容,如果未能解决你的问题,请参考以下文章
单元测试中的新核心数据堆栈(PersistenceController)
在 Laravel 中使用 MySQL 数据库连接运行多个单元测试时出错