unittest mock基本使用

 

mock介绍

mock允许用模拟对象替换系统中真实对象,并对它们已使用的方式进行断言。

在进行单元测试的时候,会遇到以下问题:
•接口的依赖;
•外部接口调用;
•测试环境非常复杂。
且单元测试应该只针对当前单元进行测试, 所有的内部或外部的依赖应该是稳定的, 已经在别处进行测试过的.使用mock 就可以对外部依赖组件实现进行模拟并且替换掉, 从而使得单元测试将焦点只放在当前的单元功能。

以下一个简单的示例:

调用mock并指定 reutrn_value 创建一个mock对象,然后mock 掉 say_hello 函数对象后,这个方法的一切动作,比如 print 就变得没有意义了,因为最后这个方法只会做一件事就是返回我们为其指定的返回值。

from unittest.mock import Mock


def say_hello(word):
    print(f"Hello {word}")

say_hello("China")
mock=Mock(return_value="PYTHON OH YEAH")
say_hello=mock
say_hello("China")

mock模块的基本使用

return_vaule 

mock 对象的 return_vaule 的作用:它将忽略 mock 对象的行为,指定其返回值。

modular.py

class Count():

    def add(self):
        pass

mock_demo01.py

from unittest import mock
import unittest

from modular import Count

# test Count class
class TestCount(unittest.TestCase):

    def test_add(self):
        count = Count()
        count.add = mock.Mock(return_value=13)
        result = count.add(8,5)
        self.assertEqual(result,13)

if __name__ == '__main__':
    unittest.main()

假设Count计算类没有实现,原本add() 方法要实现两数相加。但这个功能还没有完成。这时就可以借助mock对其进行测试。  

count = Count()

首先,调用被测试类Count() 。

count.add = mock.Mock(return_value=7)

通过Mock类模拟被调用的方法add()方法,return_value 定义add()方法的返回值。

result = count.add(2,5)

接下来,相当于在正常的调用add()方法,传两个参数2和5,然后会得到相加的结果7。然后,7的结果是我们在上一步就预先设定好的。

self.assertEqual(result,7)

最后,通过assertEqual()方法断言,返回的结果是否是预期的结果7。

side_effect

mock 对象的side_effect 的作用:通过side_effect指定mock对象的副作用,这个副作用就是当你调用这个mock对象时会调用的函数,也可以选择抛出一个异常,来对程序的错误状态进行测试。

from unittest.mock import Mock


def say_hello(word):
    print(f"Hello {word}")


mock=Mock()
#指定为函数
mock.side_effect  = say_hello
mock('china')

#指定为异常
mock.side_effect  = KeyError('This is b') #Exception("Raise Exception")
mock()

 另外也可以通过为side_effect指定一个列表,这样在每次调用时会依次返回,如下:

from unittest.mock import Mock


mock=Mock(side_effect = [1, 2, 3])
print(mock())
print(mock())
print(mock())

patch装饰器

  它是一个装饰器,需要把你想模拟的函数写在里面,然后在后面的单元测试案例中为它赋一个具体实例,再用 return_value 来指定模拟的这个函数希望返回的结果就可以了,后面就是正常单元测试代码。

@mock.pathc.object(类名,“类中函数名”)

from unittest import mock
import unittest

class Count():

    def add(self):
        pass


# test Count class
class TestCount(unittest.TestCase):

    @mock.patch.object(Count, "add")
    def test_add(self, mock_add):
        mock_add. return_value = 13
        result = mock_add()
        self.assertEqual(result,13)

if __name__ == '__main__':
    unittest.main()

@mock.pathc(模块名,“函数名”)

linux_tool.py

import re
 
def send_shell_cmd():
    return "Response from send_shell_cmd function"
 
def check_cmd_response():
    response = send_shell_cmd()
    print("response: {}".format(response))
    return re.search(r"mock_send_shell_cmd", response)

测试代码:

from unittest import TestCase, mock
import linux_tool
 
class TestLinuxTool(TestCase):
    def setUp(self):
        pass
 
    def tearDown(self):
        pass
 
    @mock.patch("linux_tool.send_shell_cmd")
    def test_check_cmd_response(self, mock_send_shell_cmd):
        mock_send_shell_cmd.return_value = "Response from emulated mock_send_shell_cmd function"
 
        status = linux_tool.check_cmd_response()
        print("check result: %s" % status)
        self.assertTrue(status)

如果 patch 多个外部函数,那么调用遵循自下而上的规则,比如:

@mock.patch("function_C")
@mock.patch("function_B")
@mock.patch("function_A")
def test_check_cmd_response(self, mock_function_A, mock_function_B, mock_function_C):
    mock_function_A.return_value = "Function A return"
    mock_function_B.return_value = "Function B return"
    mock_function_C.return_value = "Function C return"
 
    self.assertTrue(re.search("A", mock_function_A()))
    self.assertTrue(re.search("B", mock_function_B()))
    self.assertTrue(re.search("C", mock_function_C()))

一个示例

Count类中add_and_multiply依赖multiply,由于multiply并没有实现,这时候可以使用mock替换multiply:

from unittest import mock
import unittest

class Count():

    def add_and_multiply(self,x, y):
        addition = x + y
        multiple = self.multiply(x, y)
        return (addition, multiple)

    def multiply(self,x, y):
        pass


# test Count class
class TestCount(unittest.TestCase):

    @mock.patch.object(Count, "multiply")
    def test_add(self, mock_multiply):
        mock_multiply. return_value = 40
        count = Count()
        addition,multiple = count.add_and_multiply(5,8)
        self.assertEqual(addition,13)
        self.assertEqual(multiple, 40)

if __name__ == '__main__':
    unittest.main()

 

posted @ 2020-12-27 14:58  -零  阅读(2712)  评论(0编辑  收藏  举报