Reputation: 151
Based on availability of pandas package in working environment a method returns two different outputs :
pandas.DataFrame
if pandas is availablenumpy.recarray
object.How should I write unittest for this class ?
One solution I can think of is to write tests for both cases (with and without pandas installation) and skip test accordingly, something like this:
try:
import pandas
HAVE_PANDAS = True
except ImportError:
HAVE_PANDAS = False
import unittest
class TestClass(unittest.TestCase):
@unittest.skipUnless(HAVE_PANDAS, "requires pandas")
def tests_using_pandas(self):
# do something
@unittest.skipUnless(not HAVE_PANDAS, "doesn't require pandas")
def tests_without_pandas(self):
# do something
But I don't like this solution very much due to decrease in test coverage and skipping tests. I want to run my tests for both cases. It would be helpful if someone can suggest a better alternative solution for this.
Upvotes: 14
Views: 2143
Reputation: 924
import sys
from unittest.mock import patch
def test_without_panda(self):
with patch.dict(sys.modules, {'pandas': None}):
# do whatever you want
What the above code does is, it mocks that the package panda
is not installed and runs your test in that isolated environment inside the context-manager(with
).
Keep in mind, you might have to reload the module
under test depending upon your use case
import sys
from unittest.mock import patch
from importlib import reload
def test_without_panda(self):
with patch.dict(sys.modules, {'pandas': None}):
reload(sys.modules['my_module_under_test'])
# do whatever you want
Upvotes: 2
Reputation: 9968
If you want to test both cases (which you should), you could possibly force the import of Pandas to fail by adding None
to the 'pandas'
entry in sys.modules
, making sure to add it back again (or delete the entry if it didn't exist in the first place) once the test is done.
import unittest
import sys
class TestWithoutPandas(unittest.TestCase):
def setUp(self):
self._temp_pandas = None
if sys.modules.get('pandas'):
self._temp_pandas = sys.modules['pandas']
sys.modules['pandas'] = None
def tearDown(self):
if self._temp_pandas:
sys.modules['pandas'] = self._temp_pandas
else:
del sys.modules['pandas']
def tests_using_pandas(self):
flag = False
try:
import pandas
except ImportError:
flag = True
self.assertTrue(flag)
class TestWithPandas(unittest.TestCase):
def tests_using_pandas(self):
flag = False
try:
import pandas
except ImportError:
flag = True
self.assertFalse(flag)
Upvotes: 10
Reputation: 148900
IMHO, you should alway run the tests not requiring PANDAS, because nothing prevents you to.
But you should indeed skip the requiring pandas if pandas is not present at test time, because you would get uninformative errors simply caused by the absence of an optional component.
That way, when you test on your own environment (with pandas I assume), you will test both cases, but if another user wants to run the tests in an environment without pandas, it can still test the part he will use.
So my advice would be:
@unittest.skipUnless(HAVE_PANDAS, "requires pandas")
def tests_using_pandas(self):
# do something
def tests_without_pandas(self):
# do something
Upvotes: 6