【问题标题】:Unit Test can't find Core Data model file单元测试找不到核心数据模型文件
【发布时间】:2011-08-05 11:57:18
【问题描述】:

我创建了一个项目,其中包含核心数据模型。应用程序查找模型文件 (.momd) 并运行良好。

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

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

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

谢谢, -路德

【问题讨论】:

  • 感谢您提到您必须将数据模型添加到 测试项目的 编译源列表中。这就是我所缺少的。

标签: iphone cocoa xcode unit-testing ocunit


【解决方案1】:

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

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

例子:

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

【讨论】:

  • @LutherBaker 虽然这似乎是目前所有解决方案中最好的解决方法,但我认为这不是正确的答案。单元测试不应该要求修改应用程序源。因此,当您在这里访问测试用例中的捆绑包时,执行 bundleForClass: 似乎没问题,但是如果您有一些执行 [NSBundle mainBundle] 的应用程序代码(一个足够常见的习语,并且不推荐使用 AFAIK),则该类不能进行单元测试。
  • 非常感谢。为了弄清楚这一点,浪费了两天的时间!
【解决方案2】:

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

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

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

谢谢

【讨论】:

  • 这个答案也很好,因为它提供了您理解和解决问题所需的所有信息。
【解决方案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];
}

【讨论】:

    【解决方案4】:

    此方法将从任何目标获取您的捆绑包。但是,对于您添加的每个目标,您必须手动将 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;
    }
    

    【讨论】:

      【解决方案5】:

      我的问题确实是错误的Bundle!当我尝试使用框架内/框架内的数据库时,我“只需”必须从相应的 Bundle 加载数据库!

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

      // 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")
      

      瞧!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-04-24
        • 1970-01-01
        • 2016-05-12
        • 2011-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多