美文网首页
Python学习:如何使用pytest-mock(1)

Python学习:如何使用pytest-mock(1)

作者: khaos | 来源:发表于2021-09-04 23:38 被阅读0次

    1.问题

    使用pytest做python代码的测试是很容易的,不过被测试代码对网络、数据库等远程服务有依赖,这种情况该如何快速方便的进行测试。

    2.方案

    python的unitest包是支持单元测试的,有mock可以用。并且pytest-mock进行高层次的封装,用起来更加方便。安装包:

    pip3 install pytest-mock
    

    2.1.小试牛刀

    直接采用类似官方的例子,我们代码中要使用os.getcwd获取当前工作目录。只是我们的代码是在windows系统上,实际代码需要linux下工作,测试代码如下:

    import os
    
    def test_os_getcwd(mocker):
        mocker.patch("os.getcwd", return_value="/root")
        ret = os.getcwd()
        assert ret == '/root'
    

    这段代码可以测试通过。通过使用mocker.patch可以对函数进行mock。这样就本地开发环境进行测试,这也是单元测试魅力所在。

    看上去很简单对吧,实际这样例子毫无意义,实际测试根本不会这么用。网上的例子到处是这样的代码,简直是误人子弟,纯粹是浪费时间。因此才想起写一份有用的例子代码出来。

    2.2.测试自定义模块

    假设我们写了一个模块,有个函数get_pipconf_filename的路径。模块chaos的代码如下:

    import os
    
    def get_pipconf_filename():
        upath = os.path.expanduser('~')
        return upath + '/.pip/pip.conf'
    

    我们写下测试代码:

    import chaos
    
    def test_get_pipconf_filename(mocker):
        mocker.patch('os.path.expanduser',return_value='/home/chaos')
        ret = chaos.get_pipconf_filename()
        assert ret == 'home/chaos/.pip/pip.conf'
    

    问题来了,你觉得上述测试代码可以通过吗?答案是肯定的,测试通过。

    不过,如果chaos模块中是另外一种写法,上述测试还能通过吗?

    from os.path import expanduser
    
    def get_pipconf_filename():
        upath = expanduser('~')
        return upath + '/.pip/pip.conf'
    

    实际测试是失败,无法进行mock,原因就是patch打错对象了,实际上没有成功。测试代码该如何写?代码如下:

    import chaos
    
    def test_get_pipconf_filename(mocker):
        mocker.patch('chaos.expanduser', return_value='/home/chaos')
        ret = chaos.get_pipconf_filename()
        assert ret == '/home/chaos/.pip/pip.conf'
    

    这个时候应该对chaos.expanduser进行mock才行,因为chaos模块中对os.path.expanduser进行了重新赋值。

    截止到这里,给模块函数进行mock几种场景,基本能覆盖实际的测试。但问题又来了,如何根据函数调用传递的参数不同而返回不同的值呢?代码如下:

    import chaos
    
    def mock_func(s):
        if s == '~' :
            return 'home/chaos'
        else:
            return '/usr/lib'
    
    def test_get_pipconf_filename(mocker):
        mocker.patch('chaos.expanduser', side_effect=mock_func)
        ret = chaos.get_pipconf_filename('^_^')
        assert ret == '/usr/lib'
    

    上述代码使用了side_effect参数重定向到一个自定义的测试函数上。这个时候就可以根据实际的参数进行返回不同的值了。

    3.讨论

    实际上,还有一些问题没有解决?比如如何对对象进行patch,如何在初始化的时候把所有的patch都打上,不用在每个测试用例进行patch等等。留在下一篇再讲。

    Python学习:如何使用pytest-mock(2)

    相关文章

      网友评论

          本文标题:Python学习:如何使用pytest-mock(1)

          本文链接:https://www.haomeiwen.com/subject/oiblwltx.html