我正在尝试使用XCTest类和方法在Xcode 5中对我的模型进行单元测试。
因为我的模型类继承了managedObject
,所以我不能只实例化(alloc / init)它们并调用getter和setter或我需要测试的方法。
我需要使用NSEntityDescription
创建它们并使用managedObjectContext
。
就这一点而言,我遇到了麻烦。
我不知道在哪里以及如何为单元测试目的创建managedObjectContext
。
如果有人有一些建议或代码示例,那将非常有帮助。 感谢。
答案 0 :(得分: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;
}
这对我有用,因为我使用依赖注入来传递我的moc而不是使用单例。
答案 1 :(得分:12)
我同意@Abizern:在您的代码中将实例传递给NSManagedObjectContext
,而不是依赖于您的app委托,全局变量或自定义帮助器单例。
如果您知道某些控制器需要访问权限,请在其init方法中添加NSManagedObjectContext
参数并对其进行强引用:
@interface SomeController : NSObject
@property (nonatomic, strong, readwrite) NSManagedObjectContext *context;
- (instancetype)initWithContext:(NSManagedObjectContext *)context;
@end
这是执行"依赖注入"的最低要求。你不需要一个花哨的框架来为你做注射。相反,在您的应用程序中,您可以分配通常使用SQLite存储的NSManagedObjectContext
实例。在测试中,您使用内存存储创建单独的NSManagedObjectContext
并将其传递给SomeController
。这甚至适用于使用OCMock的(部分)模拟。
在objc.io#4中有一些很好的例子,特别是Chris Eidhof的示例应用程序:http://www.objc.io/issue-4/full-core-data-application.html
查看objc.io example code at GitHub,您将看到一个PersistentStack
帮助程序类,它负责初始化应用程序的托管对象上下文。 Chris使用抽象测试用例子类来提供testing context。
总体方针是:
NSManagedObjectContext
。传递托管对象并使用托管对象来访问上下文。 Florian Kugler states it this way:
托管对象应该在应用程序中传递,至少跨越模型 - 控制器障碍,甚至可能跨越控制器视图障碍。后者在某种程度上更具争议性,并且可以通过例如更好的方式进行抽象。定义一个对象必须符合的协议才能被某个视图使用,或者通过在视图类别中实现配置方法来弥合从模型对象到视图细节的差距。
无论如何,我们不应该将托管对象限制在模型层,并且只要我们想要传递它们就将它们的数据拉出到不同的结构中。托管对象是Core Data应用程序中的一等公民,我们应该相应地使用它们。例如,应在视图控制器之间传递托管对象,以便为它们提供所需的数据。
为了访问托管对象上下文,我们经常在视图控制器中看到这样的代码:
NSManagedObjectContext *context = [(MyApplicationDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
如果您已经将模型对象传递给视图控制器,那么直接通过此对象访问上下文要好得多:
NSManagedObjectContext *context = self.myObject.managedObjectContext;
这消除了对应用程序委托的隐藏依赖关系,使其更易读,也更容易测试。
这是我得到的最好的整体建议。现在,我可以在需要的地方测试核心数据的使用情况。以前,通过全局单例类(自定义类或应用程序委托)访问上下文在生产中使用很方便,但在测试中很难验证。
答案 2 :(得分:1)
NSManagedObjectContext
扩展,为测试创建内存中的CoreData
堆栈
extension NSManagedObjectContext {
class func contextForTests() -> NSManagedObjectContext {
// Get the model
let model = NSManagedObjectModel.mergedModel(from: Bundle.allBundles)!
// Create and configure the coordinator
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
try! coordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
// Setup the context
let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context.persistentStoreCoordinator = coordinator
return context
}
}
然后在测试中使用它:
class YourTests: XCTestCase {
private var context: NSManagedObjectContext?
override func setUp() {
self.context = NSManagedObjectContext.contextForTests()
}
// And use it in your tests
}