如何在python包中编写可选依赖项的unittests?

时间:2016-06-20 06:40:12

标签: python python-unittest

根据工作环境中pandas包的可用性,方法返回两个不同的输出:

  • 如果pandas可用,则为pandas.DataFrame
  • 否则为numpy.recarray对象。

我应该如何为这门课写单元测试?

我能想到的一个解决方案是为两种情况编写测试(有和没有安装pandas)并相应地跳过测试,如下所示:

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

但由于测试覆盖率和跳过测试的减少,我不太喜欢这个解决方案。我想对两种情况都进行测试。如果有人能为此提出更好的替代解决方案,将会很有帮助。

3 个答案:

答案 0 :(得分:6)

如果你想测试两种情况(你应该这样做),你可以通过将None添加到'pandas'中的sys.modules条目来强制导入Pandas失败,确保在测试完成后再次添加(或删除条目,如果它不存在于第一位)。

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)

答案 1 :(得分:5)

恕我直言,你应该总是进行不需要PANDAS的测试,因为没有什么能阻止你。

但如果pandas在测试时不存在,你应该跳过要求的pandas,因为你会因缺少可选组件而导致无法提供信息。

这样,当您在自己的环境中测试时(我假设有pandas),您将测试这两种情况,但如果另一个用户想要在没有pandas的环境中运行测试,它仍然可以测试他将使用的部分

所以我的建议是:

@unittest.skipUnless(HAVE_PANDAS, "requires pandas")
def tests_using_pandas(self):
    # do something

def tests_without_pandas(self):
    # do something

答案 2 :(得分:0)

import sys
from unittest.mock import patch

def test_without_panda(self):
    with patch.dict(sys.modules, {'pandas': None}):
        # do whatever you want

以上代码的作用是,它嘲笑未安装软件包panda,并在context-manager(with)内的隔离环境中运行测试。

请记住,根据您的用例,您可能必须重新加载受测试的module

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