XCTest和CoreData

Max*_*lle 15 unit-testing core-data ios xctest

我试图通过使用XCTest类和方法在Xcode 5中对我的模型进行单元测试.

因为我的模型类继承managedObject,我不能只是实例化(alloc/init)它们并调用getter和setter或我需要测试的方法.我需要使用NSEntityDescription和创建它们并使用a managedObjectContext.

就这一点而言,我遇到了麻烦.我不知道在哪里以及如何创建managedObjectContext用于单元测试的目的.

如果有人有一些建议或代码示例,那将非常有帮助.谢谢.

Abi*_*ern 12

我使用内存存储来进行单元测试并在其中创建所有实体.

这个类方法可以放在 TestsHelper.m

+ (NSManagedObjectContext *)managedObjectContextForTests {
    static NSManagedObjectModel *model = nil;
    if (!model) {
        model = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
    }

    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    NSPersistentStore *store = [psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:nil];
    NSAssert(store, @"Should have a store by now");

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    moc.persistentStoreCoordinator = psc;

    return moc;
}
Run Code Online (Sandbox Code Playgroud)

这对我有用,因为我使用依赖注入来传递我的moc而不是使用单例.


cti*_*tze 12

我同意@Abizern:NSManagedObjectContext在您的代码中将实例传递给周围,​​而不是依赖于您的应用委托,全局变量或自定义帮助单例.

依赖注入

如果您知道某些控制器需要访问权限,请NSManagedObjectContext在其init方法中添加一个参数并保留对它的强引用:

@interface SomeController : NSObject
@property (nonatomic, strong, readwrite) NSManagedObjectContext *context;
- (instancetype)initWithContext:(NSManagedObjectContext *)context;
@end
Run Code Online (Sandbox Code Playgroud)

这是进行"依赖注入"的最低要求.您不需要花哨的框架来为您进行注射.相反,在您的应用程序中,您可以分配NSManagedObjectContext可能使用SQLite存储的常用实例.在测试中,您NSManagedObjectContext使用内存存储创建一个单独的存储并将其传递给SomeController.这甚至适用于使用OCMock的(部分)模拟.

在objc.io#4中有一些很好的例子,特别是Chris Eidhof的示例应用程序:http://www.objc.io/issue-4/full-core-data-application.html

如何访问MOC

查看GitHub上的objc.io示例代码,您将看到一个PersistentStack帮助程序类,它负责初始化应用程序的托管对象上下文.Chris使用抽象测试用例子类来提供测试上下文.

总体方针是这样的:

  1. 不要在整个代码中依赖单例辅助类,因为很难用测试上下文替换它的上下文.这是我发现的一个特点,这是由于XCTest被"注入"正在运行的应用程序代码.网上有一些工作示例,但它们没有达到我对Xcode 5.1和XCTest的期望.
  2. 相反,NSManagedObjectContext在适当的时候准备一次.传递托管对象并使用托管对象来访问上下文.

Florian Kugler用这种方式说:

托管对象应该在应用程序中传递,至少跨越模型 - 控制器障碍,甚至可能跨越控制器视图障碍.后者在某种程度上更具争议性,并且可以通过例如定义对象必须符合的协议以便被某个视图使用,或者通过在视图类别中实现配置方法来弥补差距,从而以更好的方式进行抽象.从模型对象到视图的细节.

无论如何,我们不应该将托管对象限制到模型层,并且只要我们想要传递它们就将它们的数据拉出到不同的结构中.托管对象是Core Data应用程序中的一等公民,我们应该相应地使用它们.例如,应在视图控制器之间传递托管对象,以便为它们提供所需的数据.

为了访问托管对象上下文,我们经常在视图控制器中看到这样的代码:

NSManagedObjectContext *context = 
  [(MyApplicationDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
Run Code Online (Sandbox Code Playgroud)

如果您已将模型对象传递给视图控制器,则通过此对象直接访问上下文会更好:

NSManagedObjectContext *context = self.myObject.managedObjectContext;
Run Code Online (Sandbox Code Playgroud)

这消除了对应用程序委托的隐藏依赖性,并使其更易读,也更容易测试.

这是我得到的最好的整体建议.现在我可以在需要的地方测试核心数据的使用情况.以前,通过全局单例类(自定义类或应用程序委托)访问上下文在生产中使用很方便,但在测试中证明很难验证.