zoukankan      html  css  js  c++  java
  • Python中Mock的示例(转)

    原文:https://segmentfault.com/a/1190000008753754

    一些常用的mock示例

    先简单定义个类,方便举例:

    class Person:
        def __init__(self):
            self.__age = 10
            
        def get_fullname(self, first_name, last_name):
            return first_name + ' ' + last_name
            
        def get_age(self):
            return self.__age
            
        @staticmethod
        def get_class_name():
            return Person.__name__

    这个类里有两个成员方法,一个有参数,一个无参数。还有一个静态方法


    mock成员方法

    1. 使用Mock类,返回固定值
    class PersonTest(TestCase):
        def test_should_get_age(self):
            p = Person()
            
            # 不mock时,get_age应该返回10
            self.assertEqual(p.get_age(), 10)
            
            # mock掉get_age方法,让它返回20
            p.get_age = Mock(return_value=20)
            self.assertEqual(p.get_age(), 20)
        
        def test_should_get_fullname(self):
            p = Person()
            
            # mock掉get_fullname,让它返回'James Harden'
            p.get_fullname = Mock(return_value='James Harden')
            self.assertEqual(p.get_fullname(), 'James Harden')
    2. 校验参数个数,再返回固定值

    上面的例子你也许已经注意到了,调用p.get_fullname时没有给任何的参数,但是依然可以工作。
    如果想校验参数需要用create_autospec模块方法替代Mock类。

    class PersonTest(TestCase):
        def test_should_get_fullname(self):
            p = Person()
            
            p.get_fullname = create_autospec(p.get_fullname, return_value='James Harden')
            
            # 随便给两个参数,依然会返回mock的值
            self.assertEqual(p.get_fullname('1', '2'), 'James Harden') 
            
            # 如果参数个数不对,会报错TypeError: missing a required argument: 'last_name'
            p.get_fullname('1')
    3. 使用side_effect, 依次返回指定值
    class PersonTest(TestCase):
        def test_should_get_age(self):
            p = Person()
            
            p.get_age = Mock(side_effect=[10, 11, 12])
    
            self.assertEqual(p.get_age(), 10)
            self.assertEqual(p.get_age(), 11)
            self.assertEqual(p.get_age(), 12)
    4. 根据参数不同,返回不同的值
    class PersonTest(TestCase):
        def test_should_get_fullname(self):
            p = Person()
            
            values = {('James', 'Harden'): 'James Harden', ('Tracy', 'Grady'): 'Tracy Grady'}
            p.get_fullname = Mock(side_effect=lambda x, y: values[(x, y)])
            
            self.assertEqual(p.get_fullname('James', 'Harden'), 'James Harden')
            self.assertEqual(p.get_fullname('Tracy', 'Grady'), 'Tracy Grady')
    5. 抛出异常
    class PersonTest(TestCase):
        def test_should_raise_exception(self):
            p = Person()
            
            p.get_age = Mock(side_effect=TypeError('integer type'))
            # 只要调就会抛出异常
            self.assertRaises(TypeError, p.get_age)
    6. 检验是否调用
    class PersonTest(TestCase):
        def test_should_validate_method_calling(self):
            p.get_fullname = Mock(return_value='James Harden')
    
            # 没调用过
            p.get_fullname.assert_not_called()  # Python 3.5
    
            p.get_fullname('1', '2')
    
            # 调用过任意次数
            p.get_fullname.assert_called() # Python 3.6
            # 只调用过一次, 不管参数
            p.get_fullname.assert_called_once() # Python 3.6
            # 只调用过一次,并且符合指定的参数
            p.get_fullname.assert_called_once_with('1', '2')
    
            p.get_fullname('3', '4')
            # 只要调用过即可,必须指定参数
            p.get_fullname.assert_any_call('1', '2')
    
            # 重置mock,重置之后相当于没有调用过
            p.get_fullname.reset_mock()
            p.get_fullname.assert_not_called()
            
            # Mock对象里除了return_value, side_effect属性外,
            # called表示是否调用过,call_count可以返回调用的次数
            self.assertEqual(p.get_fullname.called, False)
            self.assertEqual(p.get_fullname.call_count, 0)
            
            p.get_fullname('1', '2')
            p.get_fullname('3', '4')
            self.assertEqual(p.get_fullname.called, True)
            self.assertEqual(p.get_fullname.call_count, 2)

    mock静态方法

    静态方法和模块方法需要使用patch来mock。

    1. 在测试方法参数中得到Mock对象
    class PersonTest(TestCase):
        # 以字符串的形式列出静态方法的路径,在测试的参数里会自动得到一个Mock对象
        @patch('your.package.module.Person.get_class_name')
        def test_should_get_class_name(self, mock_get_class_name):
            mock_get_class_name.return_value = 'Guy'
    
            self.assertEqual(Person.get_class_name(), 'Guy')
    2. 在patch中设置Mock对象
    class PersonTest(TestCase):
        mock_get_class_name = Mock(return_value='Guy')
    
        # 在patch中给出定义好的Mock的对象,好处是定义好的对象可以复用
        @patch('your.package.module.Person.get_class_name', mock_get_class_name)
        def test_should_get_class_name(self):
            self.assertEqual(Person.get_class_name(), 'Guy')
    3. 使用patch.object
    class PersonTest(TestCase):
        mock_get_class_name = Mock(return_value='Guy')
    
        # 使用patch.object来mock,好处是Person类不是以字符串形式给出的
        @patch.object(Person, 'get_class_name', mock_get_class_name)
        def test_should_get_class_name(self, ):
            self.assertEqual(Person.get_class_name(), 'Guy')
    4. 使用with控制作用域
    class PersonTest(TestCase):
        # 作用域之外,依然返回真实值
        def test_should_get_class_name(self, ):
            mock_get_class_name = Mock(return_value='Guy')
            with patch('your.package.module.Person.get_class_name', mock_get_class_name):
                self.assertEqual(Person.get_class_name(), 'Guy')
    
            self.assertEqual(Person.get_class_name(), 'Person')

    mock链式调用

    在django里,我们经常需要mock数据库,而访问数据库时经常是链式调用,看个例子。

    def get_person(name):
        return Person.objects.filter(name=name).order_by('age')

    有个模块方法,返回数据库中所有指定name的人员,并按age排序

    mock掉整个数据库访问 

    @patch('your.package.module.Person.objects.filter')
    def test_should_get_person(self, mock_filter):
        # 先得到一个filter的Mock对象,再在return_value中设置一个Mock对象,此时不需要自己再创建
        mock_filter.return_value.order_by.return_value = None
        
        self.assertIsNone(get_person())
  • 相关阅读:
    软件测试人员的年终绩效考核怎么应对
    收藏
    顶踩组件 前后两版
    订阅组件
    hdu 1963 Investment 完全背包
    hdu 4939 Stupid Tower Defense 动态规划
    hdu 4405 Aeroplane chess 动态规划
    cf 414B Mashmokh and ACM 动态规划
    BUPT 202 Chocolate Machine 动态规划
    hdu 3853 LOOPS 动态规划
  • 原文地址:https://www.cnblogs.com/ajianbeyourself/p/8795441.html
Copyright © 2011-2022 走看看