I can not compile this code:
[verify(mockedContext) deleteObject:item1];
[verify(mockedContext) deleteObject:item2];
[verify(mockedContext) save:anything()];<--compilation error for conversion id to NSError**
However I'm able to pass compilation in similar case with given
macros with additional syntax:
[[given([mockedContext save:nil]) withMatcher:anything()] willReturn:nil];
Are there anything to help me pass compilation with verify?
Here is compilation error:
Implicit conversion of an Objective-C pointer to 'NSError *__autoreleasing *' is disallowed with ARC
I assume the
save:
method on the 'mockedContext' takes a pointer-to-pointer to NSError.So actually, the NSError must be seen as an extra return value of the
save:
method. This means that you should rather setup an expectation in the first place.I worked out a small example:
We start with the Context protocol with a simple method taking an
NSError**
.Next is a class using this protocol, much like your SUT. I called it ContextUsingClass
As you can see, when the context method
doWithError:
returns an error, the recordedError property is set to YES. This is something we can expect to be true or false in our test. The only problem is, how do we tell the mock to result in an error (or to succeed without error)?The answer is fairly straight forward, and was almost part of your question: we pass an OCHamcrest matcher to the
given
statement, which in turn will set the error for us through a block. Bear with me, we'll get there. Let's first write the fitting matcher:This matcher will call the
errorSettingBlock
if it has been set, and will always return YES as it accepts all items. The matchers sole purpose is to set the error, when the test asks as much. From OCMockito issue 22 and it's fix, we learn that pointer-to-pointers are wrapped inNSValue
objects, so we should unwrap it, and cast it to our well knownNSError **
Now finally, here is how the test looks:
Conclusion
When you call methods within your SUT which are returning errors through pointer-to-pointers, you should probably test for the different possible outcomes, rather than just verifying if the method has been called.
If your SUT is ignoring the error, then let the block you pass into the matcher keep a boolean flag to indicate that it was called like so:
Or with simple verification:
PS: Ignoring errors is probably something you don't want to do...