2011-04-14 24 views
16

İçinde bir Çekirdek Veri modeliyle bir proje oluşturdum. Uygulama, model dosyasını (.momd) arar ve iyi çalışır.Birim Test Çekirdek Veri model dosyasını bulamıyor

Maalesef birim test dönen tutar sıfır:

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

Ben ana hedefi ve birim test hedefin Derleme Kaynaklar dizininde İKİ içinde myDataModel.xdatamodeld klasör ve dosya görebilirsiniz - ama bu görünmüyor yeterli olmak. Birim test hedefinde başka neleri özlüyorum?

sayesinde -Luther

+1

Veri modelinizi * test projesinin * Derlenmiş Kaynaklar listesine eklemeniz gerektiğini bildirdiğiniz için teşekkür ederiz. Bu benim eksik olduğum şey. – d512

cevap

32

Ne yazık ki, bir birim sınama hedefi uygulamanın ana paketini kullanmaz, ancak özel bir UnitTest paketi oluşturur. Bu nedenle, testlerinizde paketlenmiş kaynakları (Çekirdek Veri modeli gibi) kullanmanız gerekiyorsa, bu sorunu çözmeye çalışmanız gerekir.

En basit ve en esnek geçici çözüm, NSBundle test kodunuzda bundleForClass: yöntemini kullanıyor olabilir. Bu yöntemin parametresi, testleriniz içinde [self class] tarafından verilebilir. Bu şekilde, çoklu kodlarda paket tanımlayıcılarını ayarlamak zorunda kalmadan bu kodu yeniden kullanabilirsiniz. Örnek

:

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

Sonunda! Doğru cevap!:) –

+1

@LutherBaker Bu, şu an için tüm çözümler arasında en iyi çözüm gibi gözükse de, bunun doğru * cevap olduğunu düşünmüyorum. Birim testi, uygulama kaynağını değiştirmek için bir tane gerektirmemelidir. Bu yüzden burada test örneğindeki demete erişiyorsunuz, bir 'bundleForClass:' yapmak iyi görünüyor, ancak bir [[NSBundle mainBundle] '(ortak bir deyim olan ve AFAIK'i kullanımdan kaldırmaz) kullanan bazı uygulama kodlarınız varsa Bu sınıf birim test edilemez. – Manav

+0

Çok teşekkür ederim. Bunu çözmek için iki katı gün kaybettim! – user798719

6

cevap demetine ile ilgisi var. Bir birim test hedefi, 'ana' paketi kullanmaz. Benim durumumda, "com.yoursource.UnitTest" - varsayılan olarak [Target] -info.plist'inden çıkarılan kendi paketini oluşturur.

düzeltilmiş çözelti daha sonra şuna benzer:

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

Teşekkür

+0

Teşekkürler, sadece ihtiyacım olan bilgiler! – theory

+0

Bu yanıt da iyidir, çünkü sorunu anlamak ve düzeltmek için ihtiyacınız olan tüm bilgileri sağlar. –

2

Bu yöntem herhangi bir hedeften Paketinizi alacak. Ancak, eklediğiniz her hedef için, programlı olarak almanın bir yolu olmadığından plist bundle tanımlayıcısını el ile identifiers dizisine eklemeniz gerekir. Avantajı, uygulamayı test etmek veya çalıştırmak için aynı kodu kullanabilmenizdir.

+(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

i OCMock çerçevesini kullanarak çözmüş, benzer bir sorun vardı, bu yüzden Benim sorunum gerçekten yanlış Paketi oldu

@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

uygulama kodunu değiştirmek gerek yoktu ! Ben bir çerçeve içinde bir veritabanı kullanmaya çalıştığım gibi ben 'basitçe' db ilgili Bundle dan yüklemek zorunda! İşte

Swift4 bazı kod MagicalRecord kullanıyor:

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

Ve voilà!