【问题标题】:How do I mock a class in a Python unit test?如何在 Python 单元测试中模拟一个类?
【发布时间】:2015-01-21 18:56:01
【问题描述】:

我有一堂课:

class A:
    __init__(self):
        self.b = B()

   def is_authorized(self)
      name = self.b.get_name()

      if name == 'admin':
          return True
      else:
          return False

我想编写一个单元测试来测试is_authorized 方法。问题是它需要一个 B 类的实例,因为它需要网络连接和其他东西,所以单独构造它非常复杂。我如何模拟这个类并提供只有get_name 方法的东西。这样我就可以创建A 类并测试方法。

【问题讨论】:

    标签: python testing mocking


    【解决方案1】:

    通过使用mock 库,您可以修补B 类并将其替换为MagicMock() 对象。 mock 库正是为完成此类工作而设计的,并打破了有问题的对象或真实资源的硬依赖关系。

    在您的简单示例中,完整的测试将是:

    module_a.py

    class B():
        def __init__(self):
            print("The awful B class!!!")
    
        def get_name(self):
            print("The awful B.get_name() method!!!")
    
    
    class A():
        def __init__(self):
            self.b = B()
    
        def is_authorized(self):
            name = self.b.get_name()
            if name == 'admin':
                return True
            else:
                return False
    

    module_a_test.py

    import unittest
    from unittest.mock import patch
    from module_a import A
    
    
    class MyTestCase(unittest.TestCase):
    
        # patch B class in a_module by a MagicMock instance
        # mock_b_constructor passed to test method
        @patch("module_a.B")
        def test_a(self, mock_b_constructor):
            # B() return value will be the B() instance assigned to a.b property
            mock_b = mock_b_constructor.return_value
            # Now start test:
            a = A()
            # Ok! b is our mock...
            self.assertIs(a.b, mock_b)
            # Not authorized
            self.assertFalse(a.is_authorized())
            mock_b.get_name.return_value = 'admin'
            # Yeah!!! we are admin
            self.assertTrue(a.is_authorized())
            # Sanity check
            mock_b.get_name.return_value = 'guest'
            self.assertFalse(a.is_authorized())
    

    Patch 将只为您的测试方法上下文而存在。这是一个简单直接的示例,说明了如何使用来自mock 的模拟和补丁,但实际情况可能稍微复杂一些。

    【讨论】:

      【解决方案2】:

      为 B 创建一个模拟类,例如:

      class MockB(object):
          def get_name(self):
              return 'admin'
      

      然后,在您的测试用例中,将 A 包装在一个使用 MockB 而不是常规 B 初始化的类中:

      class TestA(A):
          def __init__(self):
              self.b = MockB()
      

      不过,老实说,我不确定这能证明什么。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-29
        • 2012-10-15
        • 2017-06-14
        相关资源
        最近更新 更多