patrick
patrick

Reputation: 9742

OCMock failures "Another mock is already associated with object" with XCTest in XCode 7

I just upgraded to XCode 7 recently, forcing me to upgrade OCMock so that I have support for x64 architectures. Apparently a change was made in OCMock which does not allow for a previously mocked object to be remocked-- in other words, I had a helper method that did something like this:

-(MyObject *)getObject {
    Factory *factory = [self.dependencyInjector getInstance:factory];
    id mockFactory = [OCMockObject partialMockForObject:factory];
    [[[mockFactory stub] andReturn:@"important-value"] thing];
    return [[MYObject alloc] initWithFactory:mockFactory];
}

This worked fine previously, but apparently there was a change to OCMockObject to not allow a re-mocking of an already mocked object. Since the factory object returned by the injector is effectively a singleton, subsequent calls to the getObject method is calling partialMockForObject: on it multiple times and this now throws an exception "Another mock is already associated with object".

Is there any way to make OCMock not throw an error? I tried calling stopMocking on the object prior to mocking it, but that does not fix this issue. The only way around it was to do something like:

-(MyObject *)getObject {
    if (!self.mockFactory) {
        Factory *factory = [self.dependencyInjector getInstance:factory];
        id mockFactory = [OCMockObject partialMockForObject:factory];
        [[[mockFactory stub] andReturn:@"important-value"] thing];
        self.mockFactory = mockFactory;
    }
    return [[MYObject alloc] initWithFactory:self.mockFactory];
}

which is really annoying to have to do...

Upvotes: 0

Views: 1322

Answers (2)

Ian Rahman
Ian Rahman

Reputation: 315

I ran into this issue and it turned out to be a race condition.

The mock was instantiated using a common factory that was injected into a class under test. The class under test performed some action and then called the factory to create the mock object on a global queue without any consistent thread specified.

The solution I went with was to create a static instance of the mocked object and reuse it throughout my tests.

Upvotes: 0

Erik Doernenburg
Erik Doernenburg

Reputation: 3014

Looking at the code as it is today, the implementation of stopMocking explicitly resets the associated object (https://github.com/erikdoe/ocmock/blob/dd5599695dcc50afe4d6bdff509ed3cbe389c667/Source/OCMock/OCPartialMockObject.m#L80). I'm at a loss how calling stopMocking doesn't solve the problem. Can you build a debug version of OCMock and set a breakpoint at the line highlighted above and see whether it's called?

Upvotes: 1

Related Questions