I'm trying to mock a call to mutableCopy
using OCMock and GHUnit on iOS.
Despite the test passing, I get an EXC_BAD_ACCESS
exception during the cleanup, and I'm trying to work out why.
Take a look at this. This test shows that it is possible to mock mutableCopy
on a mock NSString
. In this test I return another NSString
, not an NSMutableString
. This is just to demonstrate that the mutableCopy
expectation is fired, and the test passes.
#import <GHUnitIOS/GHUnit.h>
#import "OCMock.h"
@interface TestItClass : GHTestCase @end
@implementation TestItClass
// Test that mutableCopy on an NSString is mockable.
- (void)test_1_mutableCopyOfString_shouldBeMockable_givenAStringIsReturned {
NSString *string = [OCMockObject mockForClass:NSString.class];
NSString *copy = @"foo";
[(NSString *) [[(id) string expect] andReturn:copy] mutableCopy];
// MutableCopy is mocked to return a string, not a mutable string!
// This is clearly wrong from a static typing point of view, but
// the test passes anyway, which is ok.
NSMutableString *result = [string mutableCopy];
GHAssertEquals(result, copy, nil);
[(id)string verify];
}
Now I change the mock expectation so that mutableCopy
now returns an NSMutableString
. The test still passes, but on the tear down of the test I get a EXC_BAD_ACCESS
exception.
- (void)test_2_mutableCopyOfString_shouldBeMockable_givenAMutableStringIsReturned {
NSString *string = [OCMockObject mockForClass:NSString.class];
NSMutableString *copy = [@"foo" mutableCopy];
[(NSString *) [[(id) string expect] andReturn:copy] mutableCopy];
// Now mutableCopy is mocked to return a mutable string!
// The test now blows up during the test teardown! Why?
NSMutableString *foo = [string mutableCopy];
GHAssertEquals(foo, copy, nil);
[(id)string verify];
}
@end
In both tests the verifies work, as to the asserts. This shows that both tests are well constructed and that the mock expectations are being fired as expected. However, the second test fails in the tear down with a bad memory access:
Simulator session started with process 7496
Debugger attached to process 7496
2013-03-11 18:23:05.519 UnitTests[7496:c07] TestItClass/test_2_mutableCopyOfString_shouldBeMockable_givenAMutableStringIsReturned ✘ 0.00s
2013-03-11 18:23:06.466 UnitTests[7496:c07] Re-running: TestItClass/test_2_mutableCopyOfString_shouldBeMockable_givenAMutableStringIsReturned <GHTest: 0x7793340>
Exception: EXC_BAD_ACCESS (code=1, address=0x11dfe3ea))
Can you please suggest to me why it might be happening?
Thanks, Joe
the problem your facing is caused by the fact that ARC follows the Basic Memory Management Rules. Specifically this:
You own any object you create
You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).
So the solution would be to look at the invocation selector to determine whether to retain
the returnValue
or not.
I hope this help.