Так... Я пытаюсь разбудить набор модульных тестов в своем приложении для iPhone, но у меня есть некоторые проблемы. Я пытаюсь протестировать свои образцовые классы, но они наследовались непосредственно NSManagedObject. Я уверен, что это - проблема, но я не знаю, как обойти ее.
Все создает и работает как ожидалось, но я получаю эту ошибку при вызове любого метода на классе, который я тестирую:
Unknown.m:0:0 unrecognized selector sent to instance 0xc2b120
Если я следую за этой структурой для создания моего объекта в моих тестах, я заканчиваю с другой ошибкой полностью, но это все еще не помогает мне.
Если я инстанцирую своей модели как это:
entry = [[TimeEntry alloc]
initWithEntity:nil
insertIntoManagedObjectContext:nil];
Затем я заканчиваю с этой ошибкой во времени выполнения:
An NSManagedObject of class 'TimeEntry' must have a valid NSEntityDescription.
Если я пробую его как это:
entry = [[TimeEntry alloc] init];
Затем я заканчиваю с этой ошибкой:
unrecognized selector sent to instance 0xc2b120
И если я следую за шаблоном, положенным здесь:
model = [[NSManagedObjectModel mergedModelFromBundles: nil] retain];
NSLog(@"model: %@", model);
coord = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: model];
store = [coord addPersistentStoreWithType: NSInMemoryStoreType
configuration: nil
URL: nil
options: nil
error: NULL];
ctx = [[NSManagedObjectContext alloc] init];
[ctx setPersistentStoreCoordinator: coord];
entry = (TimeEntry *)[NSEntityDescription insertNewObjectForEntityForName:@"TimeEntry" inManagedObjectContext:ctx];
Затем я получаю эту ошибку:
could not locate an entity named 'TimeEntry' in this model.
В основном мой вопрос - это: как я могу протестировать класс, который наследовался NSManagedObject?
Чтобы создать экземпляр NSManagedObject, вам понадобится сущность. Таким образом, то, что вы пробовали сначала - передать nil
для объекта или использовать голый -init
(который не поддерживается в NSManagedObject) - не сработало. Вы поступаете правильно, используя - [NSEntityDescription insertNewObjectForEntityForName: inManagedObjectContext:]
для создания объекта, вам просто нужно:
Обратите внимание, что если вы специально не хотите протестировать проверку сохранения / удаления, вам обычно не нужно добавлять постоянное хранилище к вашему координатору. (И если вы используете постоянное хранилище SQLite в своем приложении, я настоятельно рекомендую использовать его и в ваших тестах; разные типы постоянных хранилищ имеют разные характеристики производительности и поддерживаемые запросы.)
Для обеспечения того, чтобы ваша модель данных была загружен, вы найдете гораздо более плодотворным, я думаю, на самом деле указать URL-адрес для его загрузки, вместо того, чтобы просто надеяться, что вы поместили его в нужное место и что -mergedModelFromBundles:
выполнит правильная вещь. Я бы сделал его членом вашего целевого пакета модульного теста, чтобы он был скомпилирован в Ресурсы вашего пакета модульного теста.Таким образом, вы можете просто использовать соответствующий метод NSBundle, чтобы получить путь или URL-адрес к нему.
Наконец, вы захотите поместить настройку вашего стека постоянства Core Data - модель, постоянный координатор хранилища и временный контекст - в метод -setUp
в вашем тесте. кейс. Или в методе -setUp
базового класса тестового набора, если вы хотите создать более одного класса тестового набора. (То же самое, конечно, касается удаления стека сохраняемости и методов -tearDown
.)
Я создал образец для среды тестирования основных данных на github. http://github.com/mbrugger/CoreDataDependentProperties/blob/master/LPAutomatedObserving/Tests/ManagedObjectSenTestCase.m
Наследуйте свои тестовые сценарии от ManagedObjectSenTestCase.m / hier и настройте следующие две строки идентификатора пакета своим тестом и имя модели данных
NSBundle* bundle = [NSBundle bundleWithIdentifier:@"com.yourcompany.ModelTest"];
NSString* path = [bundle pathForResource:@"DataModel" ofType:@"mom"];
Примеры кода:
-(void) setUp
{
pool = [[NSAutoreleasePool alloc] init];
NSMutableSet *allBundles = [[[NSMutableSet alloc] init] autorelease];
[allBundles addObjectsFromArray:[NSBundle allBundles]];
NSBundle* bundle = [NSBundle bundleWithIdentifier:@"com.yourcompany.ModelTest"];
NSString* path = [bundle pathForResource:@"DataModel"
ofType:@"mom"];
NSURL* modelURL = [NSURL URLWithString:path];
self.model = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] autorelease];
self.coordinator = [[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.model] autorelease];
LPManagedObjectContext* tempContext = [[[NSManagedObjectContext alloc] init] autorelease];
[tempContext setPersistentStoreCoordinator:coordinator];
[tempContext setRetainsRegisteredObjects:YES];
self.context = tempContext;
}
-(void) tearDown
{
NSLog(@"BEGIN: ManagedObjectSenTestCase tearDown");
@try
{
self.context= nil;
self.model = nil;
self.coordinator = nil;
[pool release];
pool = nil;
}
@catch (NSException * e)
{
NSLog(@"%@",e);
NSLog(@"%@", [e callStackSymbols]);
NSLog(@"context reset failed!");
@throw(e);
}
NSLog(@"END: ManagedObjectSenTestCase tearDown");
}
В этом примере создается основной стек данных, и вы можете вставлять сущности в созданный контекст для тестирования.
У меня была такая же проблема. В конце концов я понял, что он не может получить мою модель, но, будучи новичком в разработке iPhone, я не смог придумать, как загрузить ее из URL, как предложил Крис.
Загрузка из пакета, из которого запускались тесты, - вот что помогло мне:
@implementation WhenWorkingWithATiming
Timing *timing;
NSManagedObjectModel *model;
NSPersistentStoreCoordinator *coordinator;
NSManagedObjectContext *context;
- (void) setUp {
NSArray *bundles = [NSArray arrayWithObject:[NSBundle bundleForClass:[self class]]];
model = [[NSManagedObjectModel mergedModelFromBundles:bundles] retain];
NSLog(@"Model: %@", model);
coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:coordinator];
timing = (Timing *)[NSEntityDescription insertNewObjectForEntityForName:@"Timing" inManagedObjectContext:context];
}
- (void) tearDown {
[context rollback];
[context release];
[coordinator release];
[model release];
}
- (void) testThatTimingIsInitialised {
STAssertNotNil(timing, @"should have a timing");
}
@end