代码之家  ›  专栏  ›  技术社区  ›  Matt Baker

从nsmanagedobject继承的单元测试模型类

  •  6
  • Matt Baker  · 技术社区  · 14 年前

    所以…我试图在我的iphone应用程序中设置单元测试,但我遇到了一些问题。我试图测试我的模型类,但它们直接从nsmanagedobject继承。我肯定这是个问题,但我不知道如何解决。

    一切都在按预期构建和运行,但在对正在测试的类调用任何方法时出现此错误:

    Unknown.m:0:0 unrecognized selector sent to instance 0xc2b120

    如果我跟随 this structure 为了在测试中创建我的对象,我最终出现了另一个错误,但它仍然没有帮助我。

    如果我像这样实例化我的模型:

    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

    如果我遵循这个模式 laid out here :

    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 回复  |  直到 14 年前
        1
  •  7
  •   Chris Hanson    14 年前

    为了实例化nsmanagedobject,您需要一个实体。所以你第一次尝试的不是 nil 对于实体或使用bare -init (nsmanagedobject上不支持)不起作用。你这样做是对的 -[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:] 要创建对象,只需:

    1. 确保实体时间项存在于数据模型中。
    2. 确保 实体 TimeEntry与 数据模型中的时间项。
    3. 确保您的数据模型实际上是由您的测试加载的。

    请注意,除非您特别想测试保存/删除验证,否则通常不需要向协调器添加持久性存储。(如果您在应用程序中使用的是sqlite持久存储,我强烈建议您在测试中也使用一个;不同的持久存储类型具有不同的性能特征和支持的查询。)

    为了确保您的数据模型被加载,您会发现实际上指定从中加载它的url会更有成效,而不是仅仅希望将它放在正确的位置 -mergedModelFromBundles: 会做正确的事。我会使它成为单元测试包目标的一员,所以它被编译到单元测试包的资源中。这样,您就可以使用适当的nsbundle方法来获取它的路径或url。

    最后,您需要将核心数据持久性堆栈的设置、模型、持久性存储协调器和临时上下文放在 -setUp 方法。或者在一个 -设置 如果要创建多个测试用例类,则为测试用例基类的方法。(删除持久性堆栈和 -tearDown 当然是方法。)

        2
  •  4
  •   Martin Brugger    14 年前

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

    此示例创建核心数据堆栈,您可以将实体插入到创建的上下文中进行测试。

        3
  •  0
  •   Jonathan Moffatt    14 年前

    我也有同样的问题。我最终发现它无法检索我的模型,但作为一个iphone开发新手,我无法按照chris的建议从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