How to test Core Data properly in Swift

纵然是瞬间 提交于 2019-12-04 22:00:53

问题


There are quite a few subjects on this already, but I have yet to find a solution that is workable for Swift (Xcode 6.2).

To test Core Data backed classes in Swift, I generate new Managed Object Contexts that I then inject into my classes.

//Given   
let testManagedObjectContext = CoreDataTestComposer.setUpInMemoryManagedObjectContext()
let testItems = createFixtureData(testManagedObjectContext) as [TestItem]
self.itemDateCoordinator.managedObjectContext = testManagedObjectContext

//When
let data = self.itemDateCoordinator.do()

//Then
XCTAssert(data.exists)

The issue comes from passing a MOC created in the Test to the class that's doing. Because entity classes are namespaced, Core Data won't fetch your the appropriate ManagedObject subclass and instead hands back a NSManagedObject set. When looping or doing anything with these objects (which in your class would be an array of test items ([TestItem]).

For example, the offending class ItemDateCoordinator would execute this loop (after pulling the relevant data from a NSFetchRequest)"

for testItem in testItems {
    testItem.doPart(numberOfDays: 10)
}

would result in:

fatal error: NSArray element failed to match the Swift Array Element type

Also, I have come across a collection of information without much of a solid answer:

  • To cast entities when creating them, I have been using a solution by Jesse, but that doesn't work on a larger scope of testing.
  • A solution has been posted on another question that involved swapping out the classes at runtime, but that hasn't worked for me with entity inheritance.
  • Is there another method to testing your objects with Core Data in this case? How do you do it?

回答1:


I was about to point you toward Swift, Core Data, and unit testing but see you've already found it. :)

That post doesn't elaborate much on where your files should exist (i.e., in which Target). You should not add NSManagedObject subclasses (or any files really) to both targets. I've found that this leads to all kinds hard discover bugs and cryptic errors.

And definitely DO NOT do this. That is a terrible hack.

Instead, make your classes public and import MyAppTarget in your XCTestCase files. Better yet, your model should be in its own framework as I mention in my recent talk (a video will be posted in a few weeks on realm.io). Doing this makes your models namespace very clear and generally easier to deal with. Then you'll need to import MyAppModel everywhere you access your managed objects.

I also have a new framework, JSQCoreDataKit that intends to make Core Data easier to use in Swift. One key part of this framework is the CoreDataStack which you can initialize using an in-memory store for your tests. There's demo app with examples, and well-commented unit tests.




回答2:


I believe this was updated recently (iOS 9/Swift 2.0) to have the testable keyword on an imported target, mean that the target's internal classes (the default) become public. From the docs:

So to add to jessesquires answer above, append @testable to your import, and this should solve the unit test errors:

@testable import MyAppTarget


来源:https://stackoverflow.com/questions/29617191/how-to-test-core-data-properly-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!