0

I am writing a unit test for the function that receives a protocol as input argument.
This function that I am testing calls some method of that protocol inside. I want to mock this protocol and that method.
To mock the protocol using OCMock I wrote the following: id<MyProtocol> myProtocol = OCMProtocolMock(@protocol(MyProtocol));

Now to mock the function I am using OCMStub. The interesting part is that the function doesn't return any value but rather gets the callback as input argument and invokes it. Here is its signature: - (void)myFunction:(void (^ _Nonnull)(NSDictionary<NSString *, NSString *> * _Nonnull))completion;

I am writing the following code to mock this function:
OCMStub([myProtocol myFunction:[OCMArg any]])._andDo(^(NSInvocation *invocation){ void (^ _Nonnull)(NSDictionary<NSString *, NSString *> * _Nonnull) completion; [invocation getArgument:&completion atIndex:0]; // Here I will invoke the completion callback with some dictionary and invoke the invocation });

However I am getting the following error: "Expected identifer or '('". The error points to the line that defines completion variable.

How can I define the function variable of signature void (^ _Nonnull)(NSDictionary<NSString *, NSString *> * _Nonnull)?

Maksym Bondarenko
  • 404
  • 1
  • 5
  • 12

2 Answers2

1

That ain't a function. It is a block!

Regardless, both functions and blocks can be treated as void * in declarations. You'll need to cast them to the appropriate type after.

But that's probably the easiest way to deal with it; extract from the invocation as a void*, cast to a block, call it.

bbum
  • 162,346
  • 23
  • 271
  • 359
  • Thanks! Could you also add an example of how to cast to a block? – Maksym Bondarenko Jun 08 '17 at 02:27
  • 1
    Thanks for noticing that it is named 'block'! I have learned how to create variables of 'block' type and it solved the problem. There is no need to declare `void *` variable and casting it to a block. As the address of the variable of a block type can be passed directly to `[NSInvocation getArgument]` – Maksym Bondarenko Jun 12 '17 at 05:00
0

Actually I was able to extract a first argument by doing the following:
OCMStub([myProtocol myFunction:[OCMArg any]])._andDo(^(NSInvocation *invocation){ void (^ completion)(NSDictionary<NSString *, NSString *> * _Nonnull); [invocation getArgument:&completion atIndex:2]; // Do other stuff });

I was just declaring a variable of 'block' type incorrectly.
And I have also realized that the first argument should be accessed by index = 2;

Maksym Bondarenko
  • 404
  • 1
  • 5
  • 12