2011-04-14 77 views
16

我已經創建了一個包含核心數據模型的項目。該應用程序查找模型文件(.momd)並運行得很好。單元測試找不到核心數據模型文件

不幸的是,單元測試不斷返回null:

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

我可以看到在這兩個主要目標和單元測試目標的編譯源代碼目錄中的myDataModel.xdatamodeld文件夾和文件 - 但是,這似乎並沒有夠了。我在單元測試目標中還缺少什麼?

感謝, -Luther

+1

感謝您提及您必須將數據模型添加到* test項目的*編譯源列表。這就是我所錯過的。 – d512 2014-04-17 20:52:51

回答

32

不幸的是,單元測試目標不使用應用程序的主包,但它創建了一個特殊的UnitTest包。因此,如果您需要在測試中使用捆綁資源(如核心數據模型),則需要解決該問題。

最簡單和最靈活的解決方法是在您的測試代碼中使用bundleForClass:方法NSBundle。該方法的參數可以在測試中簡單地由[self class]給出。這樣,您可以重複使用此代碼,而無需在多個項目中調整包標識符。

例子:

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

終於! *正確*答案!:) – 2012-04-18 18:10:54

+1

@LutherBaker雖然這似乎是目前所有解決方案中最好的解決方法,但我不認爲這是*正確答案。單元測試不應該要求修改應用程序源代碼。因此,在這裏你正在訪問測試用例中的bundle,做一個'bundleForClass:'看起來沒問題,但是如果你有一些應用代碼執行'[NSBundle mainBundle]'(一個足夠常見的習慣用法,而不是棄用的AFAIK) ,那個類不能被單元測試。 – Manav 2013-01-31 08:46:05

+0

非常感謝。試圖弄清楚這兩天失去了兩個堅實的日子! – user798719 2013-11-20 00:21:17

6

答案與捆綁做。單元測試目標不使用「主」包。它創建自己的捆綁包,在我的情況下,默認爲'com.yourcompany.UnitTest' - 直接從[Target] -info.plist中輸出。

修正的解決方案則是這樣的:

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

感謝

+0

謝謝,只是我需要的信息! – theory 2011-11-04 04:37:22

+0

這個答案也很好,因爲它提供了理解和解決問題所需的所有信息。 – 2013-01-24 12:11:12

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; 
} 
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]; 
} 
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") 

,瞧!