【问题标题】:Unit test for NSManagedObject [GHUnit]NSManagedObject [GHUnit] 的单元测试
【发布时间】:2012-11-09 09:28:46
【问题描述】:

我是 Java 开发人员,我曾经将我的 Java 实体作为 POJO 进行测试。现在,使用 Obj-C,我想对继承自 NSManagedObject 的实体执行相同的操作(我使用 CoreData 进行持久化)。

例如,我想测试我的客户实体:

-(void)myTest {
Customer *customer = [Customer alloc] init];
customer.name = @"toto";
GHAssertEqualStrings(customer.name, @"toto", @"");
}

但是我遇到的错误是:

NSInvalidArgumentException 原因:-[Customers setName:]:无法识别的选择器发送到实例...

所以我已经使用适当的数据库架构 url 在 setUp 中加载了所有 NSManagedObjectContext。现在我将我的客户实例化为它并且它可以工作:

Customers *customer = [NSEntityDescription
insertNewObjectForEntityForName:kDataBaseCustomerKey inManagedObjectContext:ctx];

但这是测试 'POJO' 的合适方法吗?我想在不加载任何模型的情况下测试我的 Customer 类,因为在这种情况下我不关心数据模型。

感谢您的建议。

问候。

【问题讨论】:

    标签: ios unit-testing nsmanagedobject gh-unit


    【解决方案1】:

    这取决于您要测试的内容。从概念上将核心数据模型与现实生活中的实现分开有些困难。所以我通常在单元测试代码中构建自己的堆栈。另一方面,如果您真的在测试仅依赖于 NSManagedObject 子类实现的代码,那么我认为您概述的方法没有任何问题。

    作为参考,如果您对如何为单元测试重新创建堆栈感兴趣,以下是我的做法。 (我刚刚注意到您使用的是GHUnit 而不是OCUnit - 它应该是相同的,但您可能需要确保该模型包含在GHUnit 应用程序的捆绑资源中。

    创建一个继承自SenTestCase 的类,并使用NSInMemoryStoreType 在那里构建您的Core Data 堆栈:

    @implementation CCFCoreDataTestCase {
        NSManagedObjectModel *_mom;
        NSPersistentStoreCoordinator *_psc;
        NSManagedObjectContext *_moc;
        NSPersistentStore *_store;
    }
    
    @synthesize managedObjectContext = _moc;
    
    - (void)setUp {
        [super setUp];
    
        NSArray *bundles = [NSArray arrayWithObject:[NSBundle bundleForClass:[self class]]];
        _mom = [NSManagedObjectModel mergedModelFromBundles:bundles];
        _psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_mom];
    
        _store = [_psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL];
        STAssertNotNil(_store,@"Unable to create in-memory store");
    
        _moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_moc setPersistentStoreCoordinator:_psc];
    }
    
    - (void)tearDown {
        [super tearDown];
        _mom = nil; _psc = nil; _moc = nil; _store = nil;
    }
    

    所有涉及核心数据的测试用例都应该继承自这个子类。假设您使用的是内存存储类型,并且每次测试都构建和拆除模型,您可以最小化任何依赖关系并从每个测试的未填充模型开始。当然,没有关于性能的承诺。

    编辑:

    我发现这篇文章在处理 Core Data 对象的单元测试时很有帮助 - Unit testing Core Data-driven apps

    编辑 2:

    Graham Lee(上述帖子的作者)有另一篇关于单元测试不依赖于模拟的 Core Data 对象的帖子。见this one我上面描述的模式和他在第二个链接中所做的比较一致。

    【讨论】:

    • 是的,我喜欢这种内存解决方案。谢谢它有效(即使使用 GHUnit)。但这意味着在我之前的解决方案中,我使用了包含现有数据的“生产”数据库?
    • 供您的编辑:这篇文章很有趣,使用该解决方案我将能够在不依赖核心数据堆栈的情况下测试我的 MockCustomer。但是..我不喜欢为每个实体创建一个 Mock 类。这不是一个沉重的解决方案吗?你怎么看?
    • 查看第二次编辑。我依赖于我描述的模式——在测试中创建一个轻量级堆栈。在您之前的解决方案中,至少对于 GHUnit,我认为您实际上并没有使用“生产”数据,这取决于您如何实例化 NSManagedObjectContext - 特别是因为 GHUnit 不知道您的应用程序的持久存储。
    • 好的,谢谢您的回答。我也会依赖你提出的模型,但是 Lee 描述的 Mock 解决方案很有趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    相关资源
    最近更新 更多