Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I test a function whose output depends on another function?

Tags:

c

unit-testing

I'm very new at testing so please let me know if I am just going off in completely the wrong direction at any point. Having said that, assume I want to test the following function, foo.

int foo(int i) {
  //Lots of code here

  i = bar();

  //Some more changes to i happen here, conditional on what bar returned

  return i;
}

In this example, both foo and bar are functions written by myself and I have already tested bar.

Since the output of foo is conditional on the output of bar, I assume that in order to test foo, I need to create a mock of bar. In order to do that, and assuming that the definition of bar is kept inside a separate source file from foo, I could create a new source file, include that instead of the one where the actual definition of bar is found, and put a mock of bar in that file.

int bar(void) {
  return HARD_CODED_VALUE;
}

However, there are 2 problems with this approach:

1) What happens if bar returns multiple values (such as an error code or an actual value) and I need to ensure that foo reacts correctly for each possibility? I can't create multiple definitions for bar. One thought I did have was to create a static int in bar and then increment it every time bar gets called. Then I just have a conditional on this int, call bar multiple times and thus return multiple values. However, I am unsure whether introducing more complex logic into a mock function is good practice or if there is a better way to achieve this:

int bar(void) {
  static int i = 0;

  i++;
  if(i == 1) {
    return HARD_CODED_VALUE_1
  }
  else if(i == 2) {
    return HARD_CODED_VALUE_2
  }
  else {
    fprintf(stderr, "You called bar too many times\n");
    exit(1);
  }
}

2) What happens if bar is in the same source file as foo? I can't redefine bar nor separate foo and bar without altering my source code which would be a real pain.

like image 217
Rupert Madden-Abbott Avatar asked Aug 01 '26 19:08

Rupert Madden-Abbott


1 Answers

Well, there are a few ways around that problem.

  • You could use preprocessor hooks to swap out bar() when a UNITTEST flag is set:

    #ifdef UNITTEST
    return mockBar();
    #else
    return bar();
    #endif
    
  • You could simulate Dependency Injection, and require a pointer to bar() as a parameter to the function. I'm not saying that's a great idea in practice, but you could do it.

    void foo( void (*bar)() ) {
    

I'm sure there are others, but that's just 2 that came off the top of my head...

like image 123
ircmaxell Avatar answered Aug 03 '26 16:08

ircmaxell



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!