Python unittest against potential infinite loop
I have a python function which if passed bad data gets caught in an infinite loop. I'd like to write a unit test to confirm that it handles bad parameters gracefully. The problem is of course that if it doesn't detect the bad parameters it won't return.
Is it acceptable to use threads to write a test for this type of thing?
import threading, unittest
import mymodule
class CallSuspectFunctionThread(threading.Thread):
def __init__(self, func, *args):
self.func = func
self.args = args
super(CallSuspectFunctionThread, self).__init__()
def run(self):
self.func(*self.args)
class TestNoInfiniteLoop(unittest.TestCase):
def test_no_infinite_loop(self):
myobj = mymodule.MyObject()
bad_args = (-1,0)
test_thread = CallSuspectFunctionThread(mybj.func_to_test, *bad_args)
test_thread.daemon = True
test_thread.start()
# fail if func doesn't return after 8 seconds
for i in range(32):
test_thread.join(0.25)
if not test_thread.is_alive():
return
self.fail("function doesn't return开发者_JAVA百科")
The only problem I see with this is that if the test fails I'm stuck with this additional thread, potentially consuming cpu and memory resources, while the remainder of the tests are executed. On the other hand, I've fixed the code and the likelihood of regression here is very slim, so I don't know if it even matters whether I include the test or not.
You can add a timeout decorator. It's good to separate the logic of your testcase from the timeout mechanism implementation. This will make your code more readable and easier to maintain.
See http://pypi.python.org/pypi/timeout .
I would add the test to test for the infinite loop, since if it hangs during the tests then at least you've caught the bug before production. If the chance of it happening is slim (as you say), then i wouldn't worry about a complicated test, but I'd test the code nonetheless.
Having a test for this condition is a good idea. When code is tested, you can be more confident about it's quality.
As for the thread you create to test the function, here are two ways to kill a thread in python. Since you are inside a function that has the infinite loop, you will have to use the second method to break out of the loop.
Actually you don't have to catch it. As long as it is in your tests, you will surely notice if it goes wrong.
Maybe in your case you can solve it as the accepted answer say. Good for you. However there are cases (for integration and smoke tests, not unit tests) when you can't rule the "hangs forever" case. For these cases, I like this timeout solution.
You can't possibly test for this. What if the other thread is just "slow" or worse "livelocked" (i.e., waiting for a shared resource)? Any assumption you make can run afoul of reality.
You can't shrug and say "It always used to terminate in 1.5 seconds, but now it seems to take a little longer. I'll try 2 seconds, and see if it passes." That's just not acceptable.
You have to prove termination of all loops all the time. All loops.
Anything less is simply a design that is so poor that it should never see the light of day.
If you can't prevent and infinite loop, you're not done designing.
It's not a thing that can be tested for.
精彩评论