【问题标题】:How to write unittests for an optional dependency in a python package?如何为 python 包中的可选依赖项编写单元测试?
【发布时间】:2016-10-21 07:50:12
【问题描述】:

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

  • pandas.DataFrame 如果 pandas 可用
  • 否则为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

但由于测试覆盖率降低和跳过测试,我不太喜欢这种解决方案。我想为这两种情况运行我的测试。如果有人可以为此提出更好的替代解决方案,那将会很有帮助。

【问题讨论】:

    标签: python python-unittest


    【解决方案1】:
    import sys
    from unittest.mock import patch
    
    def test_without_panda(self):
        with patch.dict(sys.modules, {'pandas': None}):
            # do whatever you want
    

    上面的代码所做的是,它模拟了包panda 没有安装,并在上下文管理器(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
    

    【讨论】:

      【解决方案2】:

      如果您想测试这两种情况(您应该测试),您可以通过将None 添加到sys.modules 中的'pandas' 条目来强制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)
      

      【讨论】:

        【解决方案3】:

        恕我直言,您应该始终运行不需要 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
        

        【讨论】:

          猜你喜欢
          • 2012-05-04
          • 2023-04-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-29
          • 1970-01-01
          • 2015-03-10
          相关资源
          最近更新 更多