Unit Test не удается найти файл модели Core Data
Я создал проект с моделью Core Data в нем. Приложение ищет файл модели (.momd) и работает просто отлично.
К сожалению, unit test возвращает значение null:
NSURL *dataModelURL = [[NSBundle mainBundle] URLForResource:@"myDataModel" withExtension:@"momd"];
Я могу видеть папку и файл myDataModel.xdatamodeld в BOTH главной цели и целевом целевом сервере Compile Sources - но этого, похоже, недостаточно. Что еще мне не хватает в unit test target?
Спасибо,
-Luther
Ответы
Ответ 1
К сожалению, цель unit test не использует основной комплект приложения, но создает специальный пакет UnitTest. Поэтому, если вам нужно использовать связанные ресурсы (например, модель Core Data) в рамках ваших тестов, вам необходимо обойти эту проблему.
Наиболее простым и гибким решением будет использование метода bundleForClass:
NSBundle
в вашем тестовом коде. Параметр для этого метода может быть просто задан [self class]
в рамках ваших тестов. Таким образом, вы можете повторно использовать этот код без необходимости корректировать идентификаторы пакетов в нескольких проектах.
Пример:
- (void)testBundleLocation
{
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSURL *url = [bundle URLForResource:@"myDataModel" withExtension:@"momd"];
...
}
Ответ 2
Ответ должен быть связан с пакетом. Цель unit test не использует "основной" комплект. Он создает свой собственный пакет, который, в моем случае, по умолчанию "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! Поскольку я пытался использовать базу данных из/внутри Framework, я просто 'должен загрузить db из соответствующего 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")
И вуаля!