0

I've been search around for an answer but I haven't found one. The thing is, I need to do some test cases for a program I've written in C. The thing is, some functions take in an user input which makes my test cases to wait for an input, which is not what I want.

This is one of my test cases:

void test_is_location_free() {
  Storage test_storage = new_storage();
  Item test_item;
  test_storage->inventory[5] = test_item;
  test_storage->inventory[5].loc.shelf = 'A';
  test_storage->inventory[5].loc.place = 1;

  CU_ASSERT(!is_location_free(test_storage, test_item, 'A', 1));
}

This works because is_location_free() will return false, but inside the function I have another function that will keep asking the user for a new input, until the selected location is free.

This is how it looks in the terminal, where it will wait for a new user input for the shelf:

Suite: HELPER FUNCTIONS
  Test: compare_char() ...passed
  Test: first_empty_position() ...passed
  Test: is_location_free() ...Location not empty, try again!
Shelf:

Is there any way to ignore all user inputs in total, or maybe define a future user input that my test case will use?

Thanks!

venerik
  • 5,766
  • 2
  • 33
  • 43
drante
  • 129
  • 9
  • You could use say `#define TESTING` and then `#ifdef TESTING ... #else ... #endif` to replace the inputs with prepared static data. – Weather Vane Dec 18 '14 at 17:53
  • Yeah, that might do it. Is this an okay alternative to use when it comes to test cases? I just think CUnit should have some kind of support for these types of situations! – drante Dec 18 '14 at 18:06

2 Answers2

0

Assuming that your code is getting the user input from the standard input stream, you could write the data to a file and temporarily change standard input to read from that file before calling the is_location_free function.

I think the same idea could work if user input is being read from the terminal instead (/dev/tty), but would require more effort.

Note: In this particular case, I would recommend just refactoring your code so that the is_location_free function only does what it's name suggests. Then it would be easy to test. Write a second function to add the behavior where you prompt the user if the first location didn't work. You might choose not to have CUnit tests for that second function.

Russell Reed
  • 424
  • 2
  • 8
  • Yeah, the functions are kind of messed up with all these user inputs included in them. I'm using fgets() with stdin in the function, but I'm not sure how to change it before calling it. Any way, I think the best thing would be to refactor the whole code. Thanks! – drante Dec 18 '14 at 18:22
  • As long as you don't need to go back to the original stdin stream, the freopen function will do the trick. Here's a link with more discussion on the topic: [link](http://stackoverflow.com/questions/584868/rerouting-stdin-and-stdout-from-c) – Russell Reed Dec 18 '14 at 18:39
  • "Don't mix form with function." – Weather Vane Dec 18 '14 at 18:43
  • Here's a similar question: [5740176](http://stackoverflow.com/questions/5740176/how-do-i-write-a-testing-function-for-another-function-that-uses-stdin-input) – Russell Reed Dec 18 '14 at 19:02
0

You can easily write your own version of fgets() for your unit tests. This is called mocking and is very common in unit testing. Something like this should work:

static char test_input[MAX_INPUT];

char *fgets(char *s, int size, FILE *stream)
{
  strncpy(s, test_input, size);

  return s;
}

Then rewrite your test like this:

void test_is_location_free() {
  Storage test_storage = new_storage();
  Item test_item;
  test_storage->inventory[5] = test_item;
  test_storage->inventory[5].loc.shelf = 'A';
  test_storage->inventory[5].loc.place = 1;

  strncpy(test_input, "test input data", MAX_INPUT);

  CU_ASSERT(!is_location_free(test_storage, test_item, 'A', 1));
}
Lars Ljung
  • 375
  • 2
  • 6