【问题标题】:How to use patch decorator while using mark.parametrize decorator?使用 mark.parametrize 装饰器时如何使用补丁装饰器?
【发布时间】:2021-07-19 19:02:09
【问题描述】:

我有一个测试功能,可以修补一些东西。一旦我达到超过 2 或 3 个补丁,该功能开始看起来很糟糕

def test_bla():
    with patch(...):
        with patch(...):
            with patch(...):
                # test

所以我尝试开始使用装饰器。这是我引入补丁装饰器时中断的示例测试

import pytest
from unittest.mock import patch

class Example:
    def _run(self, x):
        return x

    def run(self, x):
        return self._run(x) + 1


@pytest.mark.parametrize('x', [1])
def test_example(x):
    assert Example().run(x) == 2


@pytest.mark.parametrize('x', [1])
@patch('Example._run', return_value=0)
def test_example_failure(x):
    with pytest.raises(AssertionError):
        assert Example().run(x) == 2

这是我得到的错误:

platform linux -- Python 3.6.13, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: ..., configfile: pytest.ini
plugins: metadata-1.11.0
collected 0 items / 1 error                                                                                                                                                                                    

==================================================================================================== ERRORS ====================================================================================================
________________________________________________________________________________________ ERROR collecting test_patch.py ________________________________________________________________________________________
In test_example_failure: function uses no argument 'x'
=========================================================================================== short test summary info ============================================================================================
ERROR test_patch.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
=============================================================================================== 1 error in 0.12s ===============================================================================================

我尝试更改装饰器的顺序(正如我在一些 SO 答案中看到的那样),但这没有帮助。


我刚刚意识到的另一件事是,没有参数化的测试参数是可行的! (我调整了一些代码,因为事实证明我无法从我自己的模块中修补一个类)

import pytest                                                                                                                                                                                                   
import random                                                                                                                                                                                                   
from unittest.mock import patch                                                                                                                                                                                 
                                                                                                                                                                                                                
class Example:                                                                                                                                                                                                  
    def _run(self, x):                                                                                                                                                                                          
        return random.randint(0, 6)                                                                                                                                                                             
                                                                                                                                                                                                                
    def run(self, x):                                                                                                                                                                                           
        return self._run(x) + 1                                                                                                                                                                                 
                                                                                                                                                                                                                
                                                                                                                                                                                                                
@pytest.mark.parametrize('x', [1])                                                                                                                                                                              
def test_example(x):                                                                                                                                                                                            
    assert Example().run(x) < 7                                                                                                                                                                                 
                                                                                                                                                                                                                
                                                                                                                                                                                                                
# @pytest.mark.parametrize('x', [1])                                                                                                                                                                            
@patch('random.randint', return_value=0)                                                                                                                                                                        
def test_example_failure(x):                # <<< How the heck does this work? 'x' is not defined!!                                                                                                                                                                   
    with pytest.raises(AssertionError):                                                                                                                                                                         
        assert Example().run(x) == 2    

【问题讨论】:

    标签: python unit-testing pytest python-unittest patch


    【解决方案1】:

    @patch 正在向测试发送一个参数,MagicMoc 对象。如果你想从@pytest.mark.parametrize 发送另一个参数,你需要在测试中添加另一个参数

    @pytest.mark.parametrize('x', [1])
    @patch('Example._run', return_value=0)
    def test_example_failure(mocked_class, x):
        with pytest.raises(AssertionError):
            assert Example().run(x) == 2
    
    # randint = <MagicMock name='randint' id='2158546057008'>
    # x = 1
    

    【讨论】:

    • 所以这与使用上下文修补某些东西不同吗?即with patch(bla): foo()?我最终想用@patch () 行替换很多with patch():
    • @CIsForCookies @CIsForCookies 我对patch不是很熟悉,但据我了解;功能相同,可能设置mocked_class.side_effect = some_function
    • @CIsForCookies 还有一个用于模拟的库pytestpypi.org/project/pytest-mock
    • 这似乎是一个不错的包,但实际上大部分都与 unittest mock 几乎相同,至少从我的需求角度来看。
    猜你喜欢
    • 2017-01-31
    • 2021-12-20
    • 1970-01-01
    • 2021-11-21
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多