Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my object's weak delegate property nil in my unit tests?

I have a pretty simple setup for this unit test. I have a class that has a delegate property:

@interface MyClass : NSObject
...
@property (nonatomic, weak) id<MyDelegateProtocol> connectionDelegate;
...
@end

and I set the delegate in my test:

- (void)testMyMethod_WithDelegate {
  id delegate = mockDelegateHelper(); // uses OCMock to create a mock object
  [[delegate expect] someMethod];
  myClassIvar.connectionDelegate = delegate;
  [myClass someOtherMethod];
  STAssertNoThrow([delegate verify], @"should have called someMethod on delegate.");
}

But the delegate is not actually set on line 3 of my unit test, so #someMethod is never called. When I change it to

myClassIvar.connectionDelegate = delegate;
STAssertNotNil(myClassIvar.connectionDelegate, @"delegate should not be nil");

it fails there. I'm using ARC, so my hunch was that the weak property was being deallocated. Sure enough, changing it to strong makes the STAssertNotNil pass. But I don't want to do that with a delegate, and I don't understand why that makes a difference here. From what I've read, all local references in ARC are strong, and STAssertNotNil(delegate) passes. Why is my weak delegate property nil when the same object in a local variable is not?

like image 852
Adam Stegman Avatar asked Dec 30 '11 00:12

Adam Stegman


People also ask

What makes a unit test self validating?

Self-validating means that a test should perform operations and programmatically check for the result. For instance, if you're testing that you've written something on a file, the test itself is in charge of checking that it worked correctly. No manual operations should be done.

Should unit tests be small?

A unit can be almost anything you want it to be -- a line of code, a method, or a class. Generally though, smaller is better. Smaller tests give you a much more granular view of how your code is performing.

What makes a unit test valuable?

Unit testing provides documentationTo learn what functionality is provided by one module or another, developers can refer to unit tests to get a basic picture of the logic of the module and the system as a whole.

What is unit test consideration?

Unit testing is a software development process in which the smallest testable parts of an application, called units, are individually and independently scrutinized for proper operation. This testing methodology is done during the development process by the software developers and sometimes QA staff.


2 Answers

This is a bug in the iOS runtime. The following discussion has more detail. In a nutshell, the iOS ARC runtime can't seem to handle weak references to proxies. The OSX runtime can.

http://www.mulle-kybernetik.com/forum/viewtopic.php?f=4&t=252

As far as I understand from the discussion a bug report has been filed with Apple. If anyone has a sensible idea for a workaround...

like image 107
Erik Doernenburg Avatar answered Sep 28 '22 08:09

Erik Doernenburg


I don't really know what's happening here, but OCMock returns an autoreleased NSProxy-descendant from the mockForProtocol: method, which I think is right. Maybe ARC has problems with NSProxies? Anyway, I've overcome this problem by declaring the variable __weak:

- (void)testMyMethod_WithDelegate {
  // maybe you'll also need this modifier inside the helper
  __weak id delegate = mockDelegateHelper(); 
  ...

It really doesn't need to be __strong (the default) in this case, as it's autoreleased and you're not keeping it around...

like image 34
Jordão Avatar answered Sep 28 '22 09:09

Jordão