单元测试无法找到Core Data模型文件

时间:2011-04-14 12:05:54

标签: iphone cocoa xcode unit-testing ocunit

我已经创建了一个包含Core Data模型的项目。应用程序查找模型文件(.momd)并运行正常。

不幸的是,单元测试不断返回null:

NSURL *dataModelURL = [[NSBundle mainBundle] URLForResource:@"myDataModel" withExtension:@"momd"];

我可以在主目标和单元测试目标的Compile Sources目录中看到myDataModel.xdatamodeld文件夹和文件 - 但这似乎不够。我在单元测试目标中还缺少什么?

谢谢, -Luther

5 个答案:

答案 0 :(得分:35)

不幸的是,单元测试目标不使用应用程序的主bundle,但它会创建一个特殊的UnitTest-bundle。因此,如果您需要在测试中使用捆绑资源(如核心数据模型),则需要解决该问题。

最简单,最灵活的解决方法是在测试代码中使用bundleForClass: NSBundle方法。该方法的参数可以在测试中由[self class]简单地给出。这样,您可以重用此代码,而无需在多个项目中调整包标识符。

示例:

- (void)testBundleLocation
{
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    NSURL *url = [bundle URLForResource:@"myDataModel" withExtension:@"momd"];
    ...
}

答案 1 :(得分:6)

答案与捆绑包有关。单元测试目标不使用'main'包。它创建了自己的bundle,在我的例子中,默认为'com.yourcompany.UnitTest' - 直接来自[Target] -info.plist。

修正后的解决方案如下所示:

NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.yourcompany.UnitTests"];
NSURL *url = [bundle URLForResource:@"myDataModel" withExtension:@"momd"];

由于

答案 2 :(得分:3)

有类似的问题,我使用OCMock框架解决了它,所以我不需要更改应用程序代码

@interface TestCase()
    @property (nonatomic, strong) id bundleMock;
@end

@implementation TestCase

- (void)setUp
{
    self.bundleMock = [OCMockObject mockForClass:[NSBundle class]];
    [[[self.bundleMock stub] andReturn:[NSBundle bundleForClass:[self class]]] mainBundle];
    [super setUp];
}

- (void)tearDown
{
    [self.bundleMock stopMocking];
    [super tearDown];
}

答案 3 :(得分:2)

此方法将从任何目标获取您的捆绑包。但是,对于您添加的每个目标,您必须手动将plist包标识符添加到identifiers数组,因为无法以编程方式获取它。优点是您可以使用相同的代码来测试或运行应用程序。

+(NSBundle*) getBundle 
{
    NSBundle *bundle = nil;

    // try your manually set bundles
    NSArray *identifiers = [NSArray arrayWithObjects: @"com.your.application",
                                                      @"com.your.test",
                                                      nil];
    for(NSString *bundleId in identifiers) {
        bundle = [NSBundle bundleWithIdentifier:bundleId];
        if (bundle!=nil) break;
    }

    // try the main bundle
    if (bundle==nil) bundle = [NSBundle mainBundle];

    // abort
    assert(bundle!=nil && "Missing bundle. Check the Bundle identifier on 
           the plist of this target vs the identifiers array in this class.");

    return bundle;
}

答案 4 :(得分:0)

我的问题确实是错误的捆绑!当我试图在框架内/在框架内使用数据库时,我只是'必须从相应的Bundle加载数据库!

以下是使用MagicalRecord的Swift4中的一些代码:

// Load the bundle
let frameworkBundle = Bundle(for: AClassFromTheFramework.self)
let managedObjectModel = NSManagedObjectModel.mergedModel(from: [frameworkBundle])
// Use the new `managedObjectModel` by default
MagicalRecord.setShouldAutoCreateManagedObjectModel(false)
NSManagedObjectModel.mr_setDefaultManagedObjectModel(managedObjectModel)
// Load the database 
MagicalRecord.setupCoreDataStack(withAutoMigratingSqliteStoreNamed: "db.sqlite")

瞧!