How to mute / mock C functions for iOS TDD?

I am currently creating a TDD application, but I am having problems testing the use of the C functions needed for my application. Here is an example function I need to check:

UIImageWriteToSavedPhotosAlbum(imageToBeSaved, nil, nil, nil) 

How can I make fun of or stifle method C for TDD?

+6
source share
3 answers

There are several ways to do this, but not as beautiful as in OOP languages. Here is the list I'm using:

Using Function Pointers

This approach is my favorite, because the most flexible, in my opinion.

In the header file (* .h)

 int (*_fun) (int); int fun (int a); int fun_mock (int a); 

In the sample test file (* .C)

 _fun = fun_mock; 

In the normal case file (* .C)

 _fun = fun; 

Function call (main.C)

 ... _fun (); ... 

Compilation

If you want to make TDD, you need to compile the test file and the main (or other files). Otherwise, do not compile the test file.

Using macros to replace a function name

In the header file (* .h)

If you want to call fun

 #define FUN fun int fun (int a); int fun_mock (int a); 

In the header file (* .h)

If you want to call the breadboard version

 #define FUN fun_mock int fun (int a); int fun_mock (int a); 

Function call (main.C)

 ... FUN (); ... 

Using this method, we need to establish the correct definition before compiling any of the modules.

Using a structure with a function pointer

Honestly, I never used this method, but read in other places. The main idea is to have pointers to a structure for all the various functions of the module, and whenever you want to change a function, you simply change the address of this function pointer on that structure. In the end, a similar strategy to the first method, but implemented differently.

According to Timothy Jones

test-dept is a relatively recent C module testing framework that allows you to execute functions at runtime. I found it very easy to use - here is an example from their docs:

 void test_stringify_cannot_malloc_returns_sane_result() { replace_function(&malloc, &always_failing_malloc); char *h = stringify('h'); assert_string_equals("cannot_stringify", h); } 

Despite the fact that the download section is a little outdated, it looks quite actively developed - the author fixed the problem, which I did very quickly. You can get the latest version (which I used without problems) with:

svn checkout http://test-dept.googlecode.com/svn/trunk/ test-dept-read-only version was updated in October 2011.

However, since trimming is achieved using assembler, it may take some effort to get it to support ARM.

The last point I copied from fooobar.com/questions/589598 / ....

+4
source

I like to wrap the C function in the Objective-C method so that it can be truncated / mocked / expected using falsification of Objective-C (e.g. OCMock).

SomeClass.m:

 @implementation SomeClass #pragma mark - Public // This is the method we will test. It calls a C function internally, which we want to stub. - (void)someMethod { UIImage *image = [self getImage]; [self writeImageToSavedPhotosAlbum:image completionTarget:nil completionSelector:nil contextInfo:NULL]; } #pragma mark - Private - (void)writeImageToSavedPhotosAlbum:(UIImage *)image completionTarget:(id)completionTarget completionSelector:(SEL)completionSelector contextInfo:(void *)contextInfo { UIImageWriteToSavedPhotosAlbum(image, completionTarget, completionSelector, contextInfo); } @end 

SomeClassTests.m:

 @interface SomeClass () - (void)writeImageToSavedPhotosAlbum:(UIImage *)image completionTarget:(id)completionTarget completionSelector:(SEL)completionSelector contextInfo:(void *)contextInfo; @end @interface SomeClassTests : XCTestCase @end @implementation SomeClassTests - (void)testSomeMethod { SomeClass *someInstance = [[SomeClass alloc] init]; id someInstanceMock = [OCMockObject partialMockForObject:someInstance]; [[someInstanceMock stub] writeImageToSavedPhotosAlbum:[OCMArg any] completionTarget:nil completionSelector:nil contextInfo:NULL]; [someInstance someMethod]; } @end 
+2
source

Objective-C Solution

Define a class method that returns a pointer to a C function:

 + (void (*)(UIImage *, id, SEL, void *))writeToSavedPhotosAlbumFunction { return &UIImageWriteToSavedPhotosAlbum; } 

Use the C function returned by this class method in production code:

 [SomeClass writeToSavedPhotosAlbumFunction](myImage, myTarget, mySelector, myContextInfo); 

Define a fake function C to replace the function C on which we depend:

 static void FakeWriteToSavedPhotosAlbum(UIImage *image, id completionTarget, SEL completionSelector, void *contextInfo) { // Verify arguments. // If this function has a return type, return a value. // To verify that this function was called, write to a global variable // then have the test case check the value of that global variable. } 

Run the class method to return a pointer to a fake C function in the test code ( Kiwi is used in this example):

 [SomeClass stub:@selector(writeToSavedPhotosAlbumFunction) andReturn:theValue(&FakeWriteToSavedPhotosAlbum)]; 

Hope this helps :)

+2
source

Source: https://habr.com/ru/post/945876/


All Articles