mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-11 20:00:30 +01:00
Add more info for using CoreStore in Unit Tests #39
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @tmspzz on GitHub (Feb 9, 2016).
I think adding the following information to the
README.mdwould be useful for people trying to use CoreStore in unit tests.I have the following set up and I think it's quite common.
CoreStore.beginSynchronous)Problem
The problem lies in the discrepancy between the
managedObjectClassNamereported byNSEntityDescription(gathered by CoreData from the.xcdatamodeld) and the name reported byNSStringFromClass. This causes aEXEC_BAD_ACCESSat https://github.com/JohnEstropia/CoreStore/blob/master/CoreStore/Internal/NSManagedObjectModel%2BSetup.swift#L153 .When running Unit Tests, CoreData will read the
.xcdatamodeldand fill upNSEntityDescriptionwithmanagedObjectClassNameequal to the name of the class that you have specified in your CoreData Model. By default in the corresponding CoreData Configuration this happens to be prefixed by.so if you specifyYourClassin the model, in the configuration it will show up as.YourClassinstead of justYourClass. The.means "current module". When CoreStore is building theentityNamemap at https://github.com/JohnEstropia/CoreStore/blob/master/CoreStore/Internal/NSManagedObjectModel%2BSetup.swift#L243 the map will holdYourModule.YourClassorYourModuleTests.YourClassdepending what target your are running. However when the map is accessed from your non-test target while running the unit testNSStringFromClasswill reportYourModule.YourClassas key for the map at https://github.com/JohnEstropia/CoreStore/blob/master/CoreStore/Internal/NSManagedObjectModel%2BSetup.swift#L153 and the force unwrapping will cause a memory access violation.Solution
@objc (YourClass)on top of yourNSManagedObjectsubclassclass YourClass: NSManagedObject. This will make it so thatNSStringFromClasswill returnYourClassas opposed toYourModule.YourClass.xcdatamodeldConfiguration in the Entity -> Class section enterYourClassand not.YourClassthis will remove the module name form the class@JohnEstropia commented on GitHub (Feb 9, 2016):
The problem I see is that your NSManagedObject subclass is declared in a specific module (
YourModule) while your .xcdatamodeld is declared in bothYourModuleandYourModuleTests.I suggest you either:
Modulefield in your .xcdatamodeld to your main module's name (Don't leave it atCurrent Product Module)Modulefield in your .xcdatamodeld to blank (Don't leave it atCurrent Product Module). Then set@objc (YourClass)on your NSManagedObject subclass.Target Membershipof your NSManagedObject subclass (.swift file) and your .xcdatamodeld include the same schemes. You probably need to remove them from the Unit Test scheme.As for including instructions in the README file, I don't think it is within the scope of CoreStore's usage. There's just too many configurations and it should be up to you to make your Swift class match your .xcdatamodeld.
@tmspzz commented on GitHub (Feb 10, 2016):
I see how this is not strictly relate to CoreStore but maybe a "Common Pitfalls" section would help.
I am also encountering other problems related to unit test. I am getting
I have 2 tests in the same Unit Test class which inherits form a base class where on set up I do like so:
This code is run before each and every test. Seems like the DataStack should not be initialised more than once? I would like to clear the store on every run.
@JohnEstropia commented on GitHub (Feb 10, 2016):
@blender Please refer to
CoreStoreTests.swift. There you'll see that the SQLite file is deleted every time:In
deleteStores()'s implementation:By doing so, you can start each of your test by creating a new
DataStackand overwriting any existing ones:As for your module problems, did any of the suggestions I gave solved it for you?
@tmspzz commented on GitHub (Feb 10, 2016):
Thanks for the pointers but I am using an In Memory store so I should have to need to delete anything on disk. I am trying now to just created a DataStack and hold on to it instead of assigning it to the CoreStore.defaultStack. I'll se if this solves the issue.
About the previous question I went with option 3 which seems the most clean to me.
You have a truly great README for this project, I have rarely seen such extensive documentation. Although I believe that adding a few information about how to unit test will easy the adoption of your framework.
@tmspzz commented on GitHub (Feb 10, 2016):
So in Unit Tests creating a
DataStackwith InMemoryStore and holding on to it works, as opposed to using the defaultStack in the SingletonCoreStore.defaultStack = someStackUsing the Singleton generates the following error:
@JohnEstropia commented on GitHub (Feb 11, 2016):
Thanks for the feedback!
This should be fine. Just make sure you create a new DataStack for each test and make sure you do fetches from the stack and not from
CoreStore.I think that's because you're using methods from
CoreStoreinstead of theDataStack. For example, instead of usingyou should use
The former calls
beginAsynchronous()on theCoreStore.defaultStack, which you mentioned you are not assigning to.@tmspzz commented on GitHub (Feb 11, 2016):
Yes, that was the case, I was calling methods on CoreStore directly. I think that for now I don't have anymore issues. Thanks for the help.
@JohnEstropia commented on GitHub (Feb 12, 2016):
@blender I created a separate issue to address common mistakes here
https://github.com/JohnEstropia/CoreStore/issues/48
Instead of including in the README, I'll try to catch these mistakes from within CoreStore and log suggestions how to fix them.
@winni2k commented on GitHub (Jan 8, 2017):
This was super helpful. I have been banging my head against a wall for a day on this.
I wish this issue was linked from the main
README.mdof this project.