0
votes

I am trying to mock UIImagePNGRepresentation using OCMock. UIImagePNGRepresentation accepts UIImage and returns NSData.

But it seems as you can't mock it as an ordinary function.

What I have tried is the following, but it does not compile.

id mockAlbumArt = [OCMockObject niceMockForClass:[UIImage class]];
id mockImageData = [OCMockObject niceMockForClass:[NSData class]];

id uiimageMock = [OCMockObject niceMockForClass:[UIImage class]];
[[[uiimageMock expect] andReturn:mockImageData] UIImagePNGRepresentation:mockAlbumArt];

If you look at the header for UIImage, UIImagePNGRepresentation is defined as:

UIKIT_EXTERN  NSData * __nullable UIImagePNGRepresentation(UIImage * __nonnull image);                               // return image as PNG. May return nil if image has no CGImageRef or invalid bitmap format

Has anyone done the mocking of the function before? Any help will be appreciated, thank you.

2

2 Answers

0
votes

You're right, ordinary functions can't be mocked that way.

Mocking libraries like OCMock and OCMockito provide a way to stub and verify method calls. UIImagePNGRepresentation isn't a method, it's a standalone C function.

So how do you replace it for testing? Don't invoke it directly, but through a function pointer. For normal use, assign UIImagePNGRepresentation to your pointer. For testing, assign a function you define.

0
votes

Mocking C functions similar to this can be easily achieved using a Facebook library fishhook. https://github.com/facebook/fishhook

Write a alternate method in the test file:

NSData * __nullable swizzled_UIImagePNGRepresentation(UIImage * __nonnull image)
{
    return [NSData data];
}

and then from the test function we rebind the symbols so that our method gets called instead of the original method. kind of like method swizzling.

-(void)testAlbumArt
{
     rebind_symbols((struct rebinding[1]){{"UIImagePNGRepresentation", swizzled_UIImagePNGRepresentation}}, 1); 
    ....continue and expect [NSData data] when you call UIImagePNGRepresentation...
}