Question

The code I'm working with looks something like this:-

- (MyOrange *) getAnOrangeFromBowl:(MyBowl *)bowl withSize:(NSString *)size
{
    MyOrange *orange = [bowl getAnOrangeWithSize:size];
    return orange;
}

Before you ask, no I can't just call my "MyBowl" object's method directly, it needs to be done this way for reasons unrelated to this problem.

So, I want to test that within the above method, [bowl getAnOrangeWithSize] is being called with certain parameters. I want to mock the MyBowl class as its not what's under test here, only the above method is. I also want the [bowl getAnOrangeWithSize] call to return a mock of MyOrange - in this example just for comparison purposes, but potentially I might also be doing stuff with that "orange" in the method above & I'd want to write tests on that too.

To test this I want to inject a dependency (MyBowl mock) that in turn injects another mocked dependency (MyOrange). I've run across this requirement several times and have refactored to work around it, but in this case I'm stuck.

Anyway, the test I have is:-

- (void)testThatGetAnOrangeFromBowlIsReturningAValidOrange
{
    MyOrange *mockOrange = mock([MyOrange class]);
    MyBowl *mockBowl = mock([MyBowl class]);

    [given([mockBowl getAnOrangeWithSize:@"large"]) willReturn:mockOrange];
    MyOrange *returnedOrange = [sut getAnOrangeFromBowl:mockBowl withSize:@"large"];

    assertThat(returnedOrange, is(equalTo(mockOrange)));
}

The test fails, as returnedOrange is nil. Putting a breakpoint in the code, I can see that the call to "getAnOrangeWithSize" is returning nil, so it is apparently taking no notice of the given/willReturn instructions that I specified.

I've been searching documentation & scratching my head for a while on this trying various ideas but without luck. Is there a way to get the test working, or is this something OCMockito doesn't really support (and if so, can Kiwi handle this problem)? Thanks in advance.

EDIT: It seems its possible to do this in Kiwi, as shown below:-

it(@"should return a valid Orange", ^{
    id mockOrange = [MyOrange mock];
    id mockBowl = [MyBowl mock];

    [mockBowl stub:@selector(getAnOrangeWithSize:) andReturn:mockOrange];

    MyOrange *returnedOrange = [sut getAnOrangeFromBowl:mockBowl withSize:@"whatever"];
    [[returnedOrange should] equal:mockOrange];
});

If calls to methods inside mockOrange occur in the sut's code, mockOrange could be setup as a nullMock or stubs created to handle those calls.

I am very new to Kiwi, so the above may not be optimal. I also haven't found out yet how to create a stub that only works with certain argument values passed in, so that you could create one for (using the above example) a size of @"large" returning one MyOrange instance, and @"mouldy" returning another - but I suppose that's a topic for another question if I can't find how its done.

I'd still very much like to know the OCMockito/Hamcrest equivalent of the above Kiwi code, so I'll leave this as Unanswered for now.

Was it helpful?

Solution

Your example works fine in OCMockito, so your example code isn't the problem. It's code somewhere else — or, I suspect, code that isn't present:

OCMockito uses OCHamcrest matchers for given method arguments. If the argument provided isn't a matcher, it wraps it in an equalTo(…) matcher.

But if the class in question doesn't implement -isEqual:, then the equality matcher will never be satisfied. By default, OCMockito returns nil for anything that doesn't have a matching given statement.

So either the class in question needs to implement equality, or you explicitly specify a different matcher in your given statement. In such cases, I usually use sameInstance(…) to test for identity instead of equality. Sometimes the argument itself doesn't really matter, in which case I use anything().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top