Reputation: 16309
I'm trying to use assertRaises
in a loop so I can test multiple errant delimiters ([',', ':', '-']
) without having to write a new test for each case. I'm having trouble using assertRaises
in a loop. I made a minimum working example of a unittest.TestCase
that calls assertRaises
in a loop:
import sys
import unittest
def throw_error():
sys.stderr.write('In throw error!')
raise TypeError
class Test(unittest.TestCase):
def test_loop(self):
for i in range(5):
self.assertRaises(TypeError, throw_error)
This works, but it only counts as 1 test, when I'd prefer it to be understood as 5 tests. Is there a canonical way to get this type of behavior?
>>> nosetests ../footest.py
In throw error!
In throw error!
In throw error!
In throw error!
In throw error!
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
The main reason I want this behavior is because this seems like too much of a black box, and I will eventually forget this is 5 tests in 1. Maybe writing to stderr
as I've done with a custom message is good enough, or do you have a better suggestion?
Falsetru's answer works as a standalone example, but my test_loop() function needs to be an instance method of TestCase, because there's many attributes and methods that it needs to work with. Therefore, when I adapted his answer to still use TestCase, it no longer works:
import sys
import unittest
import nose.tools as ntools
def throw_error():
sys.stderr.write('In throw error!')
raise TypeError
class Test(unittest.TestCase):
def test_loop(self):
for i in range(5):
yield ntools.assert_raises, TypeError, throw_error
This results in output of:
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Meaning throw_error()
is never called.
Upvotes: 1
Views: 683
Reputation: 6567
This is how you do it with unittest.TestCase
:
import sys
import unittest
from nose.tools import istest
def throw_error():
sys.stderr.write('In throw error!')
raise TypeError
class Test(unittest.TestCase):
pass
def _create():
""" Helper method to make functions on the fly """
@istest
def func_name(self):
self.assertRaises(TypeError, throw_error)
return func_name
def populate(cls, tests):
""" Helper method that injects tests to the TestCase class """
for index, problem in enumerate(tests):
test_method_name = '_'.join(['test', str(index)])
_method = _create()
_method.__name__ = test_method_name
_method.__doc__ = test_method_name
setattr(cls, _method.__name__, _method)
tests = range(5)
populate(Test, tests)
Here is the output:
$ nosetests -v
test_0 ... In throw error!ok
test_1 ... In throw error!ok
test_2 ... In throw error!ok
test_3 ... In throw error!ok
test_4 ... In throw error!ok
----------------------------------------------------------------------
Ran 5 tests in 0.031s
OK
Upvotes: 2
Reputation: 369074
You're using nose which supports tests generator:
from nose.tools import assert_raises
def throw_error():
raise TypeError
def test_loop():
for i in range(5):
yield assert_raises, TypeError, throw_error
Upvotes: 4