Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you write a test against a function that calls exit()?

I have a simple function which I want to test. The function goes like this:

void func()
{
    // do some work
    ...
    if(error_detected)
    {
        fatal_error("failure...");
        exit(1);
    }
}

Now I have to write a test which generates an error. Only the exit(1) exists the test with a failure, none the less!

How is this case usually handled?

I can rewrite/change the function code since I'm in full control of the entire project. However, I'm using cppunit and am hoping I can have that as one of the test in the suite.


Update:

One note that I'd like to make in regard to some of the solutions proposed: Added an interface that can be implemented differently depending on whether we are testing or not is not as strong a way to test as it may look like. Why is that? Because I would be testing with an interface which implementation is different in the test than in the real world. The result of the test does not prove that the real world situation would work right. At least not 100% (it only proves that the path is indeed taken in that particular situation.)

like image 713
Alexis Wilke Avatar asked Jun 03 '14 09:06

Alexis Wilke


People also ask

Can we mock system exit?

You actually can mock or stub out the System. exit method, in a JUnit test. Vote down reason: The problem with this solution is that if System. exit is not the last line in the code (i.e. inside if condition), the code will continue to run.

How do you test a method in java?

Test Methods: A test methods must be named testXxx() . This is because JUnit uses the reflection mechanism to find and run these methods. Inside a test method, you can use a variation of the assert() method (e.g., assertTrue() , assertFalse() , assertEquals() ) to compare the expected and actual results.


2 Answers

Normally, you should always be able to decide from the client code how your errors are handled.

Edit: consider a scenario where you write a parsing library, and a HTTP server project wants to use it. While your library may have extraordinary features, they will not be able to use it, because every time the server provides invalid inputs to your library, instead of allowing the server to report a HTTP 4XX (invalid request) error to the client, your library shuts down the whole server indiscriminately (i.e. your library calls exit() internally).

If possible in your situation, throw an exception:

void func()
{
    // do some work
    ...
    if(error_detected)
        throw std::runtime_error("failure..."); // no exit call at all
}

Production code (decide here if calling exit):

try { func(); } catch(const std::runtime_error&) { exit(1); }

Test code (no exit here):

try {
    func();
    // mark test as failed here (should not be reached)
} catch(const std::runtime_error&) {
    // mark test as passed here
}

If you cannot throw an exception in all cases (e.g. your code will be used from C code and should not throw exceptions), you can inject the error reporting code into your function:

typedef void (*on_error)(int error_code);
void func(on_error callback)
{
    // do some work
    ...
    if(error_detected)
        callback(1);
}

Production code:

void exit_on_error(int code) { exit(code); }
func(exit_on_error);

Test code:

enum { no_error = 0 };
int failed = no_error;
void on_error(int code) { failed = code; }

// test code:
func(on_error);
// check value of failed here
like image 94
utnapistim Avatar answered Nov 08 '22 14:11

utnapistim


If you are using gtest, it has a whole section dedicated to it (see Death Tests), where they say :

any test that checks that a program terminates (except by throwing an exception) in an expected fashion is also a death test.

If you are using google test, then you can test for death test using ASSERT_DEATH.

Otherwise, you need to spawn a process, execute a test, and check the result (return value of the spawned process).

like image 24
BЈовић Avatar answered Nov 08 '22 14:11

BЈовић