Swizzling new function for unit test

1k views Asked by At

Short explanation:

An object in NSDictionary seems to be over-released. Swizzling of an object's new function is involved and believed to be causing the problem.

Long explanation:

I am developing some unit-tests for code which has not been developed with unit-testing in mind. In order to replace objects created in the code with mock-objects, I am using swizzling.

I recently got the following set up:

  • I have a singleton test-class which basically just contains a dictionary of test data.
  • I have a test-case which creates a mock-object (MockA) which shall be sent to the tested function via swizzling, the function under test shall be run and the outcome examined.
  • I have a cleanup phase

Now to some code:

Testcase (Note crash!!)

- (void)testLogin
{
    [self swizzleLoginOperation];

    MockLoginOperation* op = [MockLoginOperation new];
    // *** op setup code here ***
    [[TestSingleton sharedInstance].dataToShare setObject:op forKey:LOGIN_OPERATION];

    // pseudo-code below
    [classUnderTestInstance login];

    // Assert something

    // Cleanup
    [self swizzleLoginOperation];
    [[TestSingleton sharedInstance].dataToShare removeAllObjects]; // Crash!!
}

Swizzle functions

- (void)swizzleLoginOperation
{
    Method origMethod = class_getClassMethod([LoginOperation class], @selector(new));
    Method newMethod = class_getClassMethod([MockLoginOperation class], @selector(createLoginOperationTest));

    c = object_getClass((id)[LoginOperation class]);

    if(class_addMethod(c, origSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
    {
        class_replaceMethod(c, newSel, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    }
    else
    {
        method_exchangeImplementations(origMethod, newMethod);
    }
}

+ (LoginOperation*)createLoginOperationTest
{
    NSDictionary* values = [TestSingleton sharedInstance].dataToShare;
    LoginOperation* op = (LoginOperation*)[values objectForKey:LOGIN_OPERATION];
    return op;
}

Function under test

 - (void)login
    {
        LoginOperation* op = [LoginOperation new];
        // More stuff which I have removed but still get the problem
    }

Any ideas?

Update

To find the error I attempted to run this code:

for (NSString* key in self.dataToShare.allKeys)
{
     NSObject* value = [self.dataToShare objectForKey:key]; // Crashes here
}

Crash Thread 1: EXC_BAD_ACCESS(code=1, address=…) In the log: *** -[MockLoginOperation retain]: message sent to deallocated instance 0x7fd7b31f5050

0

There are 0 answers