jonreid/OCMockito

verify macro replaces argument type with id

Opened this issue · 2 comments

If Xcode complains about multiple methods with the same name, cast verify to the mocked class.

Without the cast, autocomplete is also less helpful.

I've been able to fix both by rewriting verify:

#define verify(mock) (typeof(mock))MKTVerify(mock)

Would this be worth PRing as a change to OCMockito's own definition of verify?

Version: OCMockito v5.0.1, OCHamcrest v7.0.2

I think this is a good idea!

There's one wrinkle: propagating the type through means you now need to cast to id<MKTNonObjectArgumentMatching> or a type that conforms to that (like MKTObjectMock *) to use the -withMatcher: and -withMatcher:forArgument:.

Example of errors

Without the cast, and with propagating the type, clang issues errors like:

OCMockito/Source/Tests/VerifyObjectTests.m:139:25: error: no visible @interface for 'NSMutableArray' declares the selector 'withMatcher:forArgument:'
    [[verify(mockArray) withMatcher:greaterThan(@1) forArgument:0]
      ~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OCMockito/Source/Tests/VerifyObjectTests.m:147:25: error: no visible @interface for 'NSMutableArray' declares the selector 'withMatcher:'
    [[verify(mockArray) withMatcher:greaterThan(@1)]
      ~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~

Example of fixing the errors

The errors are fixed by casting to the type of objects conforming to the protocol:

@@ -120,7 +136,7 @@ static inline double *createArrayOf10Doubles(void)
 {
     [mockArray removeObjectAtIndex:2];

-    [[verify(mockArray) withMatcher:greaterThan(@1) forArgument:0]
+    [[(id<MKTNonObjectArgumentMatching>)verify(mockArray) withMatcher:greaterThan(@1) forArgument:0]
             removeObjectAtIndex:0];
 }

@@ -128,7 +144,7 @@ static inline double *createArrayOf10Doubles(void)
 {
     [mockArray removeObjectAtIndex:2];

-    [[verify(mockArray) withMatcher:greaterThan(@1)]
+    [[(id<MKTNonObjectArgumentMatching>)verify(mockArray) withMatcher:greaterThan(@1)]
             removeObjectAtIndex:0];
 }

Proposed enhancement

This could be made more ergonomic by adding macros like verifyWithMatcher(mock, matcher) and verifyWithMatcherForArgument(mock, matcher, index).

As a bonus, that would also make the "use a matcher for a primitive" behavior more discoverable through autocomplete of veri…. I've tripped over that primitive-related behavior a couple times already. It's easy to think you did it right when you didn't: anything() successfully matched YES in a test for me last week, but then I found this week it wasn't actually matching just anything when the method got invoked with a primitive NO in a test this week.