我目前正在对与Core Data交互的图层进行单元测试。它保存,删除和更新Item
对象。但是,我尝试保存几个Item
然后执行批量删除的测试仍然失败。
这是Item
:
extension Item {
// MARK: - Properties
@NSManaged public var date: NSDate
@NSManaged public var isTaxable: Bool
@NSManaged public var name: String
@NSManaged public var price: NSDecimalNumber
@NSManaged public var quantity: Double
// MARK: - Fetch Requests
@nonobjc public class func fetchRequest() -> NSFetchRequest<Item> { return NSFetchRequest<Item>(entityName: "Item") }
// MARK: - Validation
// Manual validation for `Decimal` values is needed. A radar is still open, which is located at https://openradar.appspot.com/13677527.
public override func validateValue(_ value: AutoreleasingUnsafeMutablePointer<AnyObject?>, forKey key: String) throws {
if key == "price", let decimal = value.pointee as? Decimal { if decimal < Decimal(0.01) { throw NSError(domain: NSCocoaErrorDomain, code: 1620, userInfo: ["Item": self]) } }
if key == "quantity", let double = value.pointee as? Double { if double == 0 { throw NSError(domain: NSCocoaErrorDomain, code: 1620, userInfo: ["Item": self]) } }
}
}
这是与核心数据CoreDataStack
交互的对象:
internal class CoreDataStack {
// MARK: - Properties
private let modelName: String
internal lazy var storeContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: self.modelName)
container.loadPersistentStores { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }
return container
}()
internal lazy var managedContext: NSManagedObjectContext = { return self.storeContainer.viewContext }()
// MARK: - Initialization
internal init(modelName: String = "Cart") { self.modelName = modelName }
// MARK: - Saving
internal func saveContext() throws {
guard managedContext.hasChanges else { return }
do { try managedContext.save() } catch let error as NSError { throw error }
}
}
这是使用Core Data管理持久性的对象:
internal final class ItemPersistenceService {
// MARK: - Properties
private let coreDataStack: CoreDataStack
// MARK: - Initialization
internal init(coreDataStack: CoreDataStack) {
self.coreDataStack = coreDataStack
print("init(coreDataStack:) - ItemPersistenceService")
}
// MARK: - Saving
@discardableResult internal func saveItem(withInformation information: ItemInformation) throws -> Item {
let item = Item(context: coreDataStack.managedContext)
item.name = information.name
item.quantity = information.quantity
item.price = information.price as NSDecimalNumber
item.date = information.date as NSDate
item.isTaxable = information.isTaxable
do {
try coreDataStack.saveContext()
} catch let error as NSError {
throw error
}
return item
}
// MARK: - Deleting
internal func delete(item: Item) throws {
coreDataStack.managedContext.delete(item)
do {
try coreDataStack.saveContext()
} catch let error as NSError {
throw error
}
}
internal func deleteAllItems() throws {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: Item.description())
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try coreDataStack.managedContext.persistentStoreCoordinator?.execute(deleteRequest, with: coreDataStack.managedContext)
} catch let error as NSError {
throw error
}
}
// MARK: - Fetching
internal func itemsCount() throws -> Int {
let fetchRequest = NSFetchRequest<NSNumber>(entityName: Item.description())
fetchRequest.resultType = .countResultType
do {
let result = try coreDataStack.managedContext.fetch(fetchRequest)
guard let count = result.first?.intValue else { fatalError("Invalid result") }
return count
} catch {
throw error
}
}
}
这是我用于测试的CoreDataStack
子类,它包含一个内存存储:
internal final class TestCoreDataStack: CoreDataStack {
// MARK: - Initialization
internal override init(modelName: String = "Cart") {
super.init(modelName: modelName)
let persistentStoreDescription = NSPersistentStoreDescription()
persistentStoreDescription.type = NSInMemoryStoreType
let container = NSPersistentContainer(name: modelName)
container.persistentStoreDescriptions = [persistentStoreDescription]
container.loadPersistentStores { (storeDescription, error) in
if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") }
self.storeContainer = container
}
}
}
最后,这是一个持续失败的测试:
internal func test_ItemPersistenceService_Delete_All_Managed_Object_Context_Saved() {
do {
try service.saveItem(withInformation: information)
try service.saveItem(withInformation: information)
} catch { XCTFail("Expected `Item`") }
expectation(forNotification: .NSManagedObjectContextDidSave, object: coreDataStack.managedContext) { (notification) in return true }
do { try service.deleteAllItems() } catch { XCTFail("Expected deletion") }
waitForExpectations(timeout: 2.0) { error in XCTAssertNil(error, "Expected save to occur") }
}
问题
NSInMemoryStoreType与NSBatchDeleteRequest不兼容吗?
如果没有,那么我做错了什么导致我的测试反复失败?
答案 0 :(得分:1)
您始终可以创建SQLite类型的持久性存储并将其存储在/dev/null
处。这是在快速XCTest
类上执行此操作的代码:
var container: NSPersistentContainer!
override func setUp() {
super.setUp()
container = NSPersistentContainer(name: "ModelName")
container.persistentStoreDescriptions[0].url = URL(fileURLWithPath: "/dev/null")
container.loadPersistentStores { (description, error) in
XCTAssertNil(error)
}
}
答案 1 :(得分:0)
我希望使用相同的方法有效地删除大量对象,但是此页面指出NSBatchDeleteRequest
仅与SQLite持久存储类型兼容,不支持内存存储类型。
重要提示:批量删除仅在您使用时才可用 SQLite持久性存储
此处列出了不同的持久性商店类型: