簡體   English   中英

Pytest:模擬具有不同 side_effect 的相同方法的多次調用

[英]Pytest: Mock multiple calls of same method with different side_effect

我有一個像下面這樣的單元測試:

# utilities.py  
def get_side_effects():
    def side_effect_func3(self):
        # Need the "self" to do some stuff at run time.
        return {"final":"some3"} 

    def side_effect_func2(self):
        # Need the "self" to do some stuff at run time.
        return {"status":"some2"}
      
    def side_effect_func1(self):
        # Need the "self" to do some stuff at run time.
        return {"name":"some1"} 

    return side_effect_func1, side_effect_func2, side_effect_func2

#################

# test_a.py
def test_endtoend():
   
    s1, s2, s3 = utilities.get_side_effects()
    
    m1 = mock.MagicMock()
    m1.side_effect = s1

    m2 = mock.MagicMock()
    m2.side_effect = s2

    m3 = mock.MagicMock()
    m3.side_effect = s3
   
    with mock.patch("a.get_request", m3):
        with mock.patch("a.get_request", m2):
            with mock.patch("a.get_request", m1):
                foo = a() # Class to test
                result = foo.run() 
    
    

作為foo.run()代碼運行的一部分,多次調用get_request 我想為get_request方法的每次調用使用不同的 side_effect 函數,在這種情況下它是side_effect_func1side_effect_func2side_effect_func3 但我注意到只有m1模擬對象處於活動狀態,即只調用side_effect_func1而不是其他 2. 我如何實現這一點?

我也嘗試了下面的方法,但是沒有調用實際的 side_effect 函數,它們總是返回function object ,但實際上並不執行 side_effect 函數。

# utilities.py
def get_side_effects():
    def side_effect_func3(self):
        # Need the "self" to do some stuff at run time.
        return {"final":"some3"} 

    def side_effect_func2(self):
        # Need the "self" to do some stuff at run time.
        return {"status":"some2"}
      
    def side_effect_func1(self):
        # Need the "self" to do some stuff at run time.
        return {"name":"some1"} 

    all_get_side_effects = []
    all_get_side_effects.append(side_effect_func1)
    all_get_side_effects.append(side_effect_func2)
    all_get_side_effects.append(side_effect_func3)
     
    return all_get_side_effects

#########################
# test_a.py
def test_endtoend():

    all_side_effects = utilities.get_side_effects()

    m = mock.MagicMock()
    m.side_effect = all_side_effects

    with mock.patch("a.get_request", m):
       foo = a() # Class to test
       result = foo.run()

您的第一次嘗試不起作用,因為每個模擬只是替換了前一個(外面的兩個模擬什么也不做)。

您的第二次嘗試不起作用,因為副作用被重載以用於可迭代對象( docs )的不同目的:

如果side_effect是一個可迭代對象,那么每次調用模擬都會從可迭代對象返回下一個值。

相反,您可以使用一個可調用的類來實現副作用,該類連續地維護有關實際調用哪個底層函數的某種狀態。

具有兩個函數的基本示例:

>>> class SideEffect:
...     def __init__(self, *fns):
...         self.fs = iter(fns)
...     def __call__(self, *args, **kwargs):
...         f = next(self.fs)
...         return f(*args, **kwargs)
... 
>>> def sf1():
...     print("called sf1")
...     return 1
... 
>>> def sf2():
...     print("called sf2")
...     return 2
... 
>>> def foo():
...     print("called actual func")
...     return "f"
... 
>>> with mock.patch("__main__.foo", side_effect=SideEffect(sf1, sf2)) as m:
...     first = foo()
...     second = foo()
... 
called sf1
called sf2
>>> assert first == 1
>>> assert second == 2
>>> assert m.call_count == 2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM