Search code examples
objective-ccore-datatddocmockmagicalrecord

Unit testing with OCMock and MagicalRecord


Although I have seen similar questions in SO, none of the answers seems to solve my problem.

I have a NSManagedObject class generated by mogenerator with custom functions (not in the model):

@interface MyManagedClass : _MyManagedClass {
-(NSNumber*)getRandomNumber2;
-(void)function_I_want_to_test;
}

My function_I_want_to_test() depend on the result of random(), and that is something I must control during testing. Since I cannot mock random() I built a function wrapper, which by the way, is not static because I had many problems with OCMock and static class functions.

The setup of my unit test looks like:

[MagicalRecord setDefaultModelFromClass:[self class]];
[MagicalRecord setupCoreDataStackWithInMemoryStore];

Using the debugger I could verify that the model is properly loaded. Also if I do it the non magical way:

    NSBundle *b = [NSBundle bundleForClass:[self class]];
    model = [NSManagedObjectModel mergedModelFromBundles:@[b]];

After this point I cannot create any mock to stub my random() wrapper function

I have tried a class mock

id mock = [OCMockObject mockForClass:[MyManagedClass class]];
[[[mock stub] andReturn:@50] getRandomNumber2];
MyManagedClass *my_object = [mock MR_createEntity];

I have tried using a partial mock

MyManagedClass *my_object = [MyManagedClass MR_createEntity];
id mock2 = [OCMockObject partialMockForObject:my_object];

After last point, just creating an instance of mock2 destroys the dynamic properties of my_object, and it become useless.

I have also tried using a mock protocol with the function I want to stub, still to no avail.

The runtime exception is the normal one other people get when using with tests with Core Data objects: the properties are not recognized selectors.

However the strange thing to me is that I am not trying to stub any dynamic property, but a normal, compile time known function. Hence it seems strange to me that using OCMock renders my instances useless.

Ideally I would like something that uses OCMock/Mogenerator/Magicalrecord.

what am I doing wrong?


Solution

  • I recommend against trying to mock out managed objects. There's a lot of runtime craziness going on to make managed objects work. That's why I suggest going with an in memory database approach for testing. This will let you create empty instances of your entities while letting the core data stuff happen.

    Since you're probably using unit tests, I suggest that in each test case where you think you need to mock out some data to instead recreate your whole stack, and set a new entity up with the state it needs to run your test. You can also make a test in memory persistent store separate from the one the default stack create method gives you, and attach this second one to your default stack. That is, make a new in memory store, initialize it with your fake/mock data entities, and attach that to your test data stack.

    I hope this rambling helps a bit, but the bottom line is dont mock managed objects...really.