Unit test for dealloc with ARC in iOS
Asked Answered
A

4

8

I'd like to write an iOS unit test for a dealloc method that (basically) removes the object as the delegate of another object.

- (void) dealloc {
    someObject.delegate = nil;
}

However I can't call dealloc directly when using ARC. What would be the best way to write this unit test?

Allergen answered 3/12, 2011 at 18:0 Comment(1)
You are also never supposed to call dealloc directly (except [super dealloc] in dealloc) when not using ARC.Hindermost
J
6

Assign an instance to a weak variable:

MyType* __weak zzz = [[MyType alloc] init];

The instance will be dealloced right away.

Alternatively, you can disable ARC on your unit test file and call dealloc.

Jacinto answered 3/12, 2011 at 18:4 Comment(3)
I don't see how you could write a useful test using a weak reference. If zzz is immediately deallocated, you'd be assigning nil as the delegate of someObject. So you'd be verifying that no-op assignment, not the behavior of deallocating zzz.Detriment
@chrispix It's true that zzz will be assigned nil, but ARC will also trigger a call to MyType's deallocation code to undo the effects of [[MyType alloc] init].Jacinto
I get that. My point is that to test that the dealloc method above nils the delegate, you need to be able to say at some point someObject.delegate = zzz. With a weak reference, that's always a nil assignment, so someObject.delegate is always nil. The test may pass, but it'll also pass if you comment that line in dealloc. I think disabling ARC on the test class is the only clean way to test this.Detriment
M
6

A better solution is simply

- (void)testDealloc
{
    __weak CLASS *weakReference;
    @autoreleasepool {
        CLASS *reference = [[CLASS alloc] init]; // or similar instance creator.
        weakReference = reference;

        // Test your magic here.
        [...]
    }
    // At this point the everything is working fine, the weak reference must be nil.
    XCTAssertNil(weakReference);
}

This works creating an instance to the class we want to deallocate inside @autorealase, that will be released (if we are not leaking) as soon as we exit the block. weakReference will hold the reference to the instance without retaining it, that will be set to nil.

Mandeville answered 12/10, 2014 at 18:41 Comment(0)
P
3

You can actually use a custom autorelease-pool to test dealloc-related behaviour:

- (void) testDealloc {
    id referencedObject = ...
    @autoreleasepool {
         id referencingObject = [ReferencingObject with:referencedObject];
         ...
    }
    // dealloc has been called on referencingObject here, unless you have a memory leak
    XCTAssertNil(referencedObject.delegate);
}
Parted answered 1/10, 2014 at 12:25 Comment(0)
C
0

In Swfit 5.3:

func test_myObject_dealloc() throws {
    weak var weakObject: MyObject?
    try autoreleasepool {
        let strongObject: MyObject = initializeMyObject(…)
        weakObject = strongObject
        XCTAssertNotNil(weakObject)
        // Perform your tests here…
    }
    XCTAssertNil(weakObject) 
}

Don't forget that you don't need the throws or try before autoreleasepool if your tests won't throw :)

Chiaki answered 23/12, 2020 at 11:6 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.