1

I am trying to write a unit test for a function that prints some texts in C. I have tried everything possible but could not make it possible. I have seen similar questions, but mostly are written in C++. Suppose one of the functions I am trying to test is the following:

void verifyStudent(char string[10][40], int lines)
{
//some actions
printf("Is our Student");
//some other actions
printf("Not a student");
}

And the test as follows:

void test_student()
{
//all initializations

char *exp_output = "Not a student";

//HOW CAN I VERIFY THAT WHAT'S PRINTED IS SAME AS THE exp-output?
}
Asusoft
  • 352
  • 2
  • 10
  • 1
    I suggest you make the test a separate program. You can send the output to a file like this: program.exe > outfile.txt and then use the testing program to read the outfile.txt to check if the output was correct or not. – Sven Nilsson Oct 27 '20 at 01:26
  • 1
    Redesign the function to separate the printing from the verification. The verification code should return a value indicating the different possible results ("Is our Student", "Not a student"), and then have a separate printing function which calls the verification function and prints the appropriate result. Testing the verification function is simpler. Mixing I/O with other logic is usually wrong. – Jonathan Leffler Oct 27 '20 at 03:37
  • Note that the function you outline is misnamed; its name should be more like `printVerificationStatusOfStudent()`, or `checkAndPrintVerificationStatusOfStudent()`. – Jonathan Leffler Oct 27 '20 at 03:39
  • In general I'd follow the hints already given in the previous comments, but in this particular case I'd also notice that `printf` [returns](https://en.cppreference.com/w/c/io/fprintf#Return_value) a value which can be used for testing porpuses. – Bob__ Oct 27 '20 at 08:48

1 Answers1

3

You can do this, by wrapping your function and redirecting output to some stream other than stdout. I will slightly change the example, but the main idea is the same. Suppose we have the following function:

void even(const int number)
{
    if(number % 2 == 0){
        printf("%d is an even number", number);
    } else{
        printf("%d is an odd number", number);
    }
}

Now we will change this to print into any stream and wrap it to keep normal performance for a user (even turn it into a static function, so the user of you library has no idea of the wrapping):

void _even(const int number, FILE* stream)
{
    if(number % 2 == 0){
        fprintf(stream, "%d is an even number", number);
    } else{
        fprintf(stream, "%d is an odd number", number);
    }
}

void even(const int number)
{
    _even(number, stdout);
}

To test _even, we can create a temporary file, redirect output of _even into it, and then check if it matches our prediction.

int test_even(const int input, const char* output)
{
    FILE* tmp = tmpfile();

    const int length = strlen(output) + 1;
    char buffer[length];

    _even(input, tmp); // Redirecting
    const int tmp_length = ftell(tmp) + 1; // how many characters are in tmp
    rewind(tmp);

    fgets(buffer, length, tmp); // Reading from tmp
    fclose(tmp);

    if(strcmp(buffer, output) == 0 && tmp_length == length){
        // Test succeded
        // Do what you want in here
    } else{
        // Test failed
    }
}

What exactly you should do when your test succeeds or fails is up to you, and up to how you design your unit testing. And you can then run it like this:

test_even(17, "17 is an odd number");   // succeeds
test_even(0, "0 is an even number");    // succeeds
test_even(-1, "-1 is an even number");  // fails
Aleksander Krauze
  • 3,115
  • 7
  • 18
  • 1
    Identifiers with two leading underscores [are reserved](https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html) for standards use. Do not use them in your code, ever. `__even` is invalid. Just `_even` or `feven` would be fine. – KamilCuk Oct 27 '20 at 08:48