Классы Модульного Тестирования, которые наследуются от NSManagedObject - PullRequest
6 голосов
/ 16 мая 2010

Итак ... Я пытаюсь настроить модульные тесты в своем приложении для 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?

Ответы [ 3 ]

7 голосов
/ 20 мая 2010

Чтобы создать экземпляр NSManagedObject, вам нужен объект. Таким образом, то, что вы впервые попробовали - либо передать nil для сущности, либо использовать голое -init (что не поддерживается в NSManagedObject) - не сработало. Вы правильно делаете, используя -[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:] для создания объекта, вам просто нужно:

  1. Убедитесь, что объект TimeEntry существует в вашей модели данных.
  2. Убедитесь, что объект TimeEntry связан с классом TimeEntry в вашей модели данных.
  3. Убедитесь, что ваша модель данных действительно загружена вашими тестами.

Обратите внимание, что если вы не хотите специально проверять сохранение / удаление проверки, вам обычно не нужно добавлять постоянное хранилище в ваш координатор. (И если вы используете постоянное хранилище SQLite в своем приложении, я настоятельно рекомендую использовать его и в ваших тестах; разные типы постоянных хранилищ имеют разные характеристики производительности и поддерживаемые запросы.)

Чтобы убедиться, что ваша модель данных загружена, вы найдете ее гораздо более плодотворной. Я думаю, что нужно указать URL для ее загрузки, вместо того, чтобы надеяться, что вы поместили ее в нужное место и что -mergedModelFromBundles: будет делать правильные вещи. Я бы сделал его членом вашей группы тестов модульных тестов, чтобы он был скомпилирован в Ресурсы вашей группы модульных тестов. Таким образом, вы можете просто использовать соответствующий метод NSBundle, чтобы получить путь или URL к нему.

Наконец, вы захотите поместить в свой тестовый пример настройку вашего стека постоянства базовых данных - модель, координатор постоянного хранилища и чистый контекст - в методе -setUp. Или в методе -setUp базового класса тестового набора, если вы хотите создать более одного класса тестового набора. (То же самое относится и к удалению стека постоянства и методов -tearDown, конечно.)

4 голосов
/ 21 мая 2010

Я создал образец для среды тестирования основных данных на github http://github.com/mbrugger/CoreDataDependentProperties/blob/master/LPAutomatedObserving/Tests/ManagedObjectSenTestCase.m

Унаследуйте ваши тестовые случаи от ManagedObjectSenTestCase.m / h и настройте следующие две строки с вашим идентификатором целевого набора теста и именем модели данных

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

В этом образце создается основной стек данных, и вы можете вставить сущности в созданный контекст для тестирования.

0 голосов
/ 25 мая 2010

У меня была такая же проблема. В конце концов я понял, что он не смог получить мою модель, но, будучи новичком в разработке для 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
...