How to write unittests for an optional dependency in a python package?
Question: Based on availability of pandas package in working environment a method
returns two different outputs :

  * A `pandas.DataFrame` if pandas is available
  * Otherwise a `numpy.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.


Answer: 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)
    

