我使用使用Core Data的Swift iOS应用程序实现了单元测试,但是我无法通过单元测试。我引用了下面链接的指南和一些堆栈溢出线程,但我仍然遇到问题。
应用程序在实际构建时运行没有缺陷,但测试失败,让我相信我已经搞砸了某个地方,整合了模拟的Core Data容器和后台持久容器。但是,我似乎无法弄清楚我在哪里出错,所以任何建议都值得赞赏。
如果我的帖子缺少任何关键细节,我道歉,但我会在必要时添加它们。
主要参考资料:Cracking the Tests for Core Data
class MealTests: XCTestCase {
var sut: MealController!
lazy var managedObjectModel: NSManagedObjectModel = {
let managedObjectModel = NSManagedObjectModel.mergedModel(from: [Bundle(for: type(of: self))])!
return managedObjectModel
}()
lazy var mockPersistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "WeeklyModel", managedObjectModel: self.managedObjectModel)
let description = NSPersistentStoreDescription()
description.type = NSInMemoryStoreType
description.shouldAddStoreAsynchronously = false
container.persistentStoreDescriptions = [description]
container.loadPersistentStores {(description, error) in
//Double check to confirm that date store is in memory
precondition(description.type == NSInMemoryStoreType)
//Check for errors
if let error = error {
fatalError("Creating an in-memory coordinator failed")
}
}
return container
}()
override func setUp() {
super.setUp()
sut = MealController(tense: .all, persistentContainer: mockPersistentContainer)
}
func test_CreatingNewMeal_IsNotNilAndPropertiesSetCorrectly() {
let mealType = Int16(1)
let date = NSDate(timeIntervalSinceNow: 0.0)
let mealDescription = "Testy McTestFace"
let servings = Int16(1)
let image = UIImage(named: "Recipe")
let favorite = false
let meal = sut.saveLocalMeal(mealType: mealType, date: date, mealDescription: mealDescription, servings: servings, image: image, favorite: favorite)
//Test meal is not nil
XCTAssertNotNil(meal, "Should not be nil")
//Testing creating meal sets all properties correctly
XCTAssertEqual(meal?.meal, mealType)
}
class MealController {
//MARK: - Properties
//<...>
private let persistentContainer: NSPersistentContainer!
private var fetchedResultsController: NSFetchedResultsController<Meal>!
lazy var backgroundMOC: NSManagedObjectContext = {
return self.persistentContainer.newBackgroundContext()
}()
//Set to standard persistence container by default
init(tense: Tense, persistentContainer: NSPersistentContainer) {
self.persistentContainer = persistentContainer
self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
reloadAllLocalData(for: tense)
}
convenience init(tense: Tense) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
fatalError("Could not set Managed Object Context")
}
self.init(tense: tense, persistentContainer: appDelegate.persistenceContainer)
}
func getMealCount() -> Int {
return fetchedResultsController.fetchedObjects?.count ?? 0
}
func getMeal(at indexPath: IndexPath) -> Meal {
return fetchedResultsController.object(at: indexPath)
}
//The boolean determines whether historical or future data is shown
func reloadAllLocalData(for tense: Tense){
let fetchRequest: NSFetchRequest<Meal> = Meal.fetchRequest()
//Setting predicate, etc.
//<...>
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: backgroundMOC, sectionNameKeyPath: nil, cacheName: nil)//Add cache to this?
do {
try fetchedResultsController.performFetch()
} catch let error {
//<...>
}
}
//Saving
func saveLocalMeal(mealType: Int16, date: NSDate, mealDescription: String, servings: Int16, image: UIImage?, favorite: Bool, comment: String? = nil, recipeUID: String? = nil) -> Meal? {
//Make new meal object
let meal = Meal(entity: Meal.entity(), insertInto: backgroundMOC)
//Call helper func and result result
return save(context: backgroundMOC, meal: meal, mealUID: nil, mealType: mealType, date: date, mealDescription: mealDescription, servings: servings, image: image, favorite: favorite, comment: comment, recipeUID: recipeUID)
}
private func save(context: NSManagedObjectContext, meal: Meal, mealUID: String?, mealType: Int16, date: NSDate, mealDescription: String, servings: Int16, image: UIImage?, favorite: Bool, comment: String? = nil, recipeUID: String? = nil) -> Meal? {
//Setting properties
//<...>
do {
try backgroundMOC.save()
return meal
} catch let error as NSError {
print("Could not save. \(error)")
return nil
}
}