Objective c 在运行iOS应用程序测试时,如何切换到内存存储?
对于核心数据对象,我有一个相当标准的Xcode生成接口,即我的应用程序委托上的以下属性:Objective c 在运行iOS应用程序测试时,如何切换到内存存储?,objective-c,ios,unit-testing,core-data,Objective C,Ios,Unit Testing,Core Data,对于核心数据对象,我有一个相当标准的Xcode生成接口,即我的应用程序委托上的以下属性: @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; @property (readonly, strong, nonatomi
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
现在我正在编写应用程序测试,但我想使用内存中的核心数据数据库,该数据库在每次测试运行时都会重置。我已经想出了一个办法,但感觉很奇怪:
- 我在app delegate类中有一个静态变量,
storeType
将其设置为-persistentstorecordinator
,如果它是NSSQLiteStoreType
。这将是默认值,并且在生产中是唯一的值,以确保在运行应用程序时一切正常nil
- 我确保为所有调试版本(包括我的应用程序测试目标)设置了
宏DEBUG
- 如果设置了
,请在应用程序委托中定义一个方法,DEBUG
。方法如下所示:-resetCoreData
#ifdef DEBUG - (void)resetCoreData { // Testing, we want to use the in memory store. storeType = NSInMemoryStoreType; // Disconnect core data. __persistentStoreCoordinator = nil; __managedObjectContext = nil; // Set up defaults. [self configureCoreDataDefaults]; } #endif
请注意,它将静态变量@interface CollectionsDAO : NSObject @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; + (CollectionsDAO *)defaultDAO; @end
设置为storeType
。nsimemorystoretype
方法创建一些应该始终存在的托管对象-configureCoreDataDefaults
- 在我的应用程序测试基类中,我有
调用-setup
:-resetCoreData
- (void)setUp { [super setUp]; [[[UIApplication sharedApplication] delegate] resetCoreData]; }
那么,有什么更好的方法可以做到这一点呢?如何操作?我建议创建DAO或类似工具来隔离核心数据设置。然后,使用一个类别,您可以在您的测试目标中定义并使用这个“resetCoreData”。是@eduardo costa的答案的后续,我已经接受了这个答案,并使用了我用来使它工作的代码 首先,我创建了一个DAO类,并将所有核心数据属性都移到了那里。.h文件如下所示:
#ifdef DEBUG
- (void)resetCoreData {
// Testing, we want to use the in memory store.
storeType = NSInMemoryStoreType;
// Disconnect core data.
__persistentStoreCoordinator = nil;
__managedObjectContext = nil;
// Set up defaults.
[self configureCoreDataDefaults];
}
#endif
@interface CollectionsDAO : NSObject
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+ (CollectionsDAO *)defaultDAO;
@end
现在我只要在需要访问核心数据的地方使用这个类-defaultDAO
返回该类的静态实例,因此我可以在任何地方使用一个实例。您没有看到的是一个私有实例方法,-storeType
,它返回NSSQLiteStoreType
。这用于创建存储。我会在下面再谈
接下来,我在这个类上创建了一个类别,用于测试。头文件:
#import "CollectionsDAO.h"
@interface CollectionsDAO (Test)
+ (void)setupTestDAO;
+ (void)clearData;
@end
以及实施:
#import "CollectionsDAO+Test.h"
#include <objc/runtime.h>
static CollectionsDAO *testDAO;
@implementation CollectionsDAO (Testing)
+ (CollectionsDAO *)testDAO {
if (testDAO == nil) testDAO = [[self alloc] init];
return testDAO;
}
+ (void)setupTestDAO {
method_setImplementation(
class_getClassMethod(self.class, @selector(defaultDAO)),
method_getImplementation(class_getClassMethod(self.class, @selector(testDAO)))
);
}
+ (void)clearData {
testDAO = nil;
}
- (NSString *)storeType {
return NSInMemoryStoreType;
}
@end
现在测试总是使用内存来存储核心数据,DAO的测试实例总是由+defaultDAO
返回(因为+setupTestDAO
将其转换到位),并且每次测试后都会清除核心数据
我觉得这比以前干净多了。我花了一段时间才弄明白,但爱德华多的答案是正确的,我只需要花一段时间来弄清楚细节。你能假设核心数据正在工作,并使用模拟存储进行测试吗?您真的需要测试核心数据吗?通过使用内存模型,我已经达到了与模拟核心数据相同的效果:每次调用后,数据都会在内存中结束,因此我可以检查它是否正确。实际上,模拟核心数据需要做更多的工作。使用类别是个好主意(为什么我总是忘记它们??),但我不知道DAO(我想是数据访问对象)是什么意思。你能详细说明一下吗?是的,数据访问对象。它只是一个具有CoreData逻辑的对象。我只是喜欢向DAO添加一个类别,而不是向我的主代理添加一个类别。另外,当我这样做时,我的代理往往会收缩很多(旧的“将应用程序分层”的事情:)。因此,问题是
-resetCoreData
主要将一些私有IVAR设置为nil
。我看不出一个简单的分类方法。为了安全使用,我希望属性保持只读。不过,我还需要再考虑一下。好的,我接受了,但我已经添加了我自己的答案,并详细说明了我是如何使它真正起作用的。谢谢你的指点!