我正在为更大的iOS应用程序编写Core Data ContextManager。 ContextManager提供了一个NSManagedContext,当其他ContextManagers将其NSMangedContext保存到持久数据存储时,它会自动更新。
我有一个单元测试(TestContextManager),它创建两个上下文,将一个对象添加到一个,并测试以查看该对象是否出现在另一个上下文中。它没有。 为什么最后一次测试失败?
这是ContextManager的代码和失败的单元测试。单元测试中的最后一个断言失败。每一个断言传递。如您所见,ContextManager依赖于从不同的ContextManager获取更改通知并使用mergeChangesFromContextDidSaveNotification
更新自身。请注意,所有内容都发生在此测试的同一个线程上。
我知道正在发送和接收NSManagedObjectContextDidSaveNotification。我知道NSManagedObjectContextDidSaveNotification在其userInfo字典中有正确的数据。
我还使用SQLite持久存储在实际设备上运行此单元测试作为应用程序测试 - 相同的断言失败。
提前致谢!
ContextManager:
#import "ContextManager.h"
@implementation ContextManager
@synthesize context;
#pragma mark - Custom code
- (void)save {
NSError *error = nil;
if (self.context != nil) {
if ([self.context hasChanges] && ![self.context save:&error]) {
NSAssert1(FALSE, @"Unable to save the managed object context. UserInfo:\n%@", [error userInfo]);
}
}
return;
}
- (void)mergeChanges:(NSNotification *)notification {
if (notification.object != self.context) {
[self.context mergeChangesFromContextDidSaveNotification:notification];
}
return;
}
#pragma mark - Overridden NSObject methods
#pragma mark Creating, copying, and deallocating object
- (id)initWithPersistentStoreCoordinator:(NSPersistentStoreCoordinator *)persistentStoreCoordinator {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:nil];
self.context = [[[NSManagedObjectContext alloc] init] autorelease];
[self.context setPersistentStoreCoordinator:persistentStoreCoordinator];
}
return self;
}
- (void)dealloc {
[context release];
[super dealloc];
return;
}
@end
TestContextManager来:
#import "TestContextManager.h"
#import "ContextManager.h"
#import "CoreDataManager.h"
#define TEST_MANAGED_OBJECT @"AManagedObject"
@implementation TestContextManager
- (void)testContextManager {
CoreDataManager *coreDataManager = [[CoreDataManager alloc] init];
coreDataManager.storeType = NSInMemoryStoreType;
ContextManager *contextManagerA = [coreDataManager provideContextManager];
if (!contextManagerA) STFail(@"CoreDataManager did not provide a context manager.");
NSManagedObjectContext *contextA = contextManagerA.context;
if (!contextA) STFail(@"ContextManager did not provide a managed object context.");
// setA1 has 0 objects (or whatever is initially there).
NSSet *setA1 = [contextManagerA.context registeredObjects];
[NSEntityDescription insertNewObjectForEntityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextManagerA.context];
// setA2 has 1 object.
NSSet *setA2 = [contextManagerA.context registeredObjects];
STAssertTrue([setA2 count] == [setA1 count]+1, @"Context provided by ContextManager is not accepting new objects.");
[contextManagerA save];
ContextManager *contextManagerB = [coreDataManager provideContextManager];
[NSEntityDescription insertNewObjectForEntityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextManagerB.context];
[contextManagerB save];
NSSet *setA3 = [contextManagerA.context registeredObjects];
// setA3 should have 2 objects <=== THIS TEST FAILS
STAssertTrue([setA3 count] == [setA1 count]+2, @"Context is not updating new objects.");
[coreDataManager release];
return;
}
@end
答案 0 :(得分:1)
您是否实际设置了ContextManager来观察保存managedObjectContext的通知?你没有在这里展示,所以我只想介绍最简单的案例。
抱歉 ,我应该对Erik的帖子发表评论。
答案 1 :(得分:1)
感谢您回答我的问题鲜为人知。显然,我需要阅读registeredObjects
实际返回的内容。我想这里的好消息是实际代码有效 - 单元测试很糟糕......
这是正确测试被测单位并通过的单元测试:
#import "TestContextManager.h"
#import "ContextManager.h"
#import "CoreDataManager.h"
#define TEST_MANAGED_OBJECT @"AManagedObject"
@implementation TestContextManager
- (void)testContextManager {
CoreDataManager *coreDataManager = [[CoreDataManager alloc] init];
coreDataManager.storeType = NSInMemoryStoreType;
ContextManager *contextManagerA = [coreDataManager provideContextManager];
if (!contextManagerA) STFail(@"CoreDataManager did not provide a context manager.");
NSManagedObjectContext *contextA = contextManagerA.context;
if (!contextA) STFail(@"ContextManager did not provide a managed object context.");
NSEntityDescription *entityDescriptionA = [NSEntityDescription entityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextA];
// make A1 request on an empty context (0 objects)
NSFetchRequest *requestA1 = [[NSFetchRequest alloc] init];
[requestA1 setEntity:entityDescriptionA];
NSError *errorA1 = nil;
NSArray *arrayA1 = [contextA executeFetchRequest:requestA1 error:&errorA1];
if (arrayA1 == nil) STFail(@"Fetch request A1 failed.");
if ([arrayA1 count] != 0) STFail(@"Context A1 is not empty at start of test.");
// add an object to context A and make request A2
[NSEntityDescription insertNewObjectForEntityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextManagerA.context];
NSFetchRequest *requestA2 = [[NSFetchRequest alloc] init];
[requestA2 setEntity:entityDescriptionA];
NSError *errorA2 = nil;
NSArray *arrayA2 = [contextA executeFetchRequest:requestA2 error:&errorA2];
if (arrayA2 == nil) STFail(@"Fetch request A2 failed.");
if ([arrayA2 count] != 1) STFail(@"Context A2 did not successfully add an object.");
// add an object to context B and make request B1
ContextManager *contextManagerB = [coreDataManager provideContextManager];
NSManagedObjectContext *contextB = contextManagerB.context;
NSEntityDescription *entityDescriptionB = [NSEntityDescription entityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextB];
[NSEntityDescription insertNewObjectForEntityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextManagerB.context];
NSFetchRequest *requestB1 = [[NSFetchRequest alloc] init];
[requestB1 setEntity:entityDescriptionB];
NSError *errorB1 = nil;
NSArray *arrayB1 = [contextB executeFetchRequest:requestB1 error:&errorB1];
if (arrayB1 == nil) STFail(@"Fetch request B1 failed.");
if ([arrayB1 count] != 1) STFail(@"Context B1 did not successfully add an object.");
// save contextB
[contextManagerB save];
// check if contextA was updated
NSFetchRequest *requestA3 = [[NSFetchRequest alloc] init];
[requestA3 setEntity:entityDescriptionA];
NSError *errorA3 = nil;
NSArray *arrayA3 = [contextA executeFetchRequest:requestA3 error:&errorA3];
if (arrayA3 == nil) STFail(@"Fetch request A3 failed.");
if ([arrayA3 count] != 2) STFail(@"Context A did not update correctly.");
[requestA1 release];
[requestA2 release];
[requestB1 release];
[requestA3 release];
[coreDataManager release];
return;
}
@end