3

I'm trying to add unit tests to an existing iOS application, using among others OCMock.

In this application, we have a bunch of CoreData entities and generated classes. These classes obviously contain @dynamic properties.

I tried to stub one of these properties as follows:

self.event = [OCMockObject mockForClass:[ACEvent class]];
[[[self.event stub] andReturn:@"e46e1555-d866-4160-9b42-36d0fb9c29cd"] eventGUID];

The point is, it doesn't work. Apparently because an @dynamic property does not have an implementation by default, and in this case relies on CoreData to provide it. I end up with a NSError:

-[NSProxy doesNotRecognizeSelector:eventGUID] called!

I've seen other questions where this has been solved by abstracting the CoreData entity behind a protocol (OCMock with Core Data dynamic properties problem). But since this is an existing code base, I don't have this option, as I can't afford to refactor everything.

Can anyone provide another solution to this?

EDIT: As a side note, I just found a solution, but I'm worried it could not work in all cases. What I did is provide a sample, empty implementation for these methods in the test target. It works, but I'm worried it could break other tests that rely on CoreData to work. Any insight on this?

Community
  • 1
  • 1
aspyct
  • 3,625
  • 7
  • 36
  • 61
  • Using an empty method in a category should work. The reason why OCMock needs an implementation is that is has to figure out what the method signature is. Once it knows that the stub should work. Maybe we could add something that would let OCMock assume a method with no arguments and an id return type if it can't find a method in the mocked class. That seems a bit fragile, though. – Erik Doernenburg Jun 20 '13 at 12:45

2 Answers2

3

With OCMock I always create a protocol for each managed object, and then create mocks for those protocols, but as you said you cannot do that, so I suggest to create a fake class with the same properties you are using in the code you want to test(for each NSManagedObject), and then just use a cast when passing those fake objects (either you use OCMock and stub the methods you want or just create a object of the fake class and set the properties you want).

e1985
  • 6,239
  • 1
  • 24
  • 39
2

The above answer didn't satisfy me, because I didn't like to create a protocol for that. So I found out that there is an easier way to do that. Instead of

[[[self.event stub] andReturn:@"e46e1555-d866-4160-9b42-36d0fb9c29cd"] eventGUID];

Just write

[[[self.event stub] andReturn:@"e46e1555-d866-4160-9b42-36d0fb9c29cd"] valueForKey:@"eventGUID"];
user2963938
  • 131
  • 1
  • 2
  • Just tried this using the latest version of OCMock. It didn't work. It appears that core data doesn't use valueForKey:. :-( – drekka Oct 15 '14 at 05:10