2

I'm not sure if that was the best title, but basically I know that a variable will become instantiated upon running a function. I want to do a partial mock of this variable and expect certain method calls before the variable is instantiated. Here's an example of what I'm trying to do.

-(void)testMethod {
    id mockVar = [OCMock partialMockForObject:self.controller.variable];
    [[mockVar expect] someMethod];

    [self.controller method];
    [mockVar verify];
}

The method inside the controller will look something like:

-(void)method {
    self.variable = [[Class alloc]init];
    [self.variable someMethod];
}

I'm receiving a message like 'doesNotRecognizeSelector'. Is this possible?

Ryan Schulze
  • 87
  • 2
  • 10
  • You can't create a mock if your object is `nil`. OCMock is doing a bunch of introspection in its setup of the mock object, none of which will produce any results for `nil`. That said, what's the full error message/backtrace? – jscs Oct 09 '13 at 19:58
  • error: testMethod (ControllerTests) failed: *** -[NSProxy doesNotRecognizeSelector:someMethod:] called! – Ryan Schulze Oct 09 '13 at 20:18
  • @JoshCaswell So if the object is nil before the 'method' is executed, is there any way to expect a method call in this situation? – Ryan Schulze Oct 09 '13 at 20:19
  • Not that I can see, but I'll poke around when I get a chance... – jscs Oct 09 '13 at 20:28

2 Answers2

1

It feels like a weird test, but it's possible if you mock the accessor:

-(void)testMethod {
    id mockVar = [OCMock mockForClass:[Class class]];
    id mockController = [OCMock partialMockForObject:controller];
    [[[mockController stub] andReturn:mockVar] variable];
    [[mockVar expect] someMethod];

    [self.controller method];
    [mockVar verify];
}

If you provide a more concrete example of what you're trying to achieve, I could give you a better answer.

Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92
  • Tried this and works fine, but I was trying to access the variable that would eventually exist, not mock it. Thanks for your solution! – Ryan Schulze Oct 17 '13 at 16:11
1

If stubbing the property accessor is a possibility, I would go with that. But if you need to partial mock the instance actually created by the real code, it's possible provided it gets stored on the property -- the setter method becomes the hook -- but it's definitely ugly.

The basic idea is to use OCMArg's checkWithBlock: functionality to intercept the argument to the set method, and create the partial mock at that point. You can assign it to a variable outside the block for verification later on. It would look something like this:

-(void)testMethod
{
    id mockController = [OCMockObject partialMockForObject:self.controller];
    __block id mockVar;

    [[[mockController stub] andForwardToRealObject] setVariable:[OCMArg checkWithBlock:^BOOL(id param) {
        mockVar = [OCMockObject partialMockForObject:param];
        [[mockVar expect] someMethod];
        return YES;
    }]];

    [self.controller method];  // mockVar will be created and assigned during this call
    [mockVar verify];
}

If your real code creates an object and only stores it temporarily in a local variable (not an instance variable), there is really nothing you can do, aside from restructuring your real code to make it easier to test (such as moving the code which creates the object into a new method, which makes it much easier to stub).

Carl Lindberg
  • 2,902
  • 18
  • 22