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?

Leo
  • 37,640
  • 8
  • 75
  • 100
hpique
  • 119,096
  • 131
  • 338
  • 476
  • You are also never supposed to call `dealloc` directly (except `[super dealloc]` in `dealloc`) when not using ARC. – newacct Oct 01 '14 at 19:43

4 Answers4

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.

7ynk3r
  • 958
  • 13
  • 17
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.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 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`. – Christopher Pickslay Dec 05 '11 at 19:28
  • @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]`. – Sergey Kalinichenko Dec 05 '11 at 19:42
  • 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. – Christopher Pickslay Dec 05 '11 at 21:55
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);
}
Leo
  • 37,640
  • 8
  • 75
  • 100
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 :)

Roger Oba
  • 1,292
  • 14
  • 28