簡體   English   中英

Python:在單元測試期間如何覆蓋復雜的函數?

[英]Python: how can I override a complicated function during unittest?

我正在使用Python的unittest模塊來測試正在編寫的腳本。

該腳本包含如下循環:

// my_script.py

def my_loopy_function():
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + complicated_function(x)
    return aggregate_value

def complicated_function(x):
    a = do()
    b = something()
    c = complicated()
    return a + b + c

我使用沒有問題unittest來測試complicated_function 不過,我想測試my_loopy_function通過重寫complicated_function

我試圖修改我的腳本,以便my_loopy_function需要complicated_function作為可選參數,這樣我可以從測試的簡單版本通過:

// my_modified_script.py

def my_loopy_function(action_function=None):
    if action_function is not None:
        complicated_function = action_function
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + complicated_function(x)
    return aggregate_value

def complicated_function(x):
    a = do()
    b = something()
    c = complicated()
    return a + b + c

// test_my_script.py

from myscript import my_loopy_function

class TestMyScript(unittest.TestCase):
    test_loopy_function(self):
        def simple_function():
            return 1
    self.assertEqual(10, my_loopy_function(action_function=simple_function))

它沒有按我希望的那樣工作,是否有關於如何進行此操作的建議?

不要試圖重寫complicated_functionaction_function ,只需使用complicated_function作為默認action_function

def my_loopy_function(action_function=complicated_function):
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + action_function(x)
    return aggregate_value

最后,我使用了Python的mock ,它使我可以覆蓋complicated_function而不必以任何方式調整原始代碼。

這里是原始腳本,並注意complicated_function不傳遞給my_loopy_function作為“ action_function ”參數(這是我在我的早期解決方案試過):

// my_script.py

def my_loopy_function():
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + complicated_function(x)
    return aggregate_value

def complicated_function(x):
    a = do()
    b = something()
    c = complicated()
    return a + b + c

這是我用來測試的腳本:

// test_my_script.py

import unittest
import mock
from my_script import my_loopy_function

class TestMyModule(unittest.TestCase):
    @mock.patch('my_script.complicated_function')
    def test_1(self, mocked):
        mocked.return_value = 1
        self.assertEqual(10, my_loopy_function())

就像我想要的那樣工作:

  1. 我可以用更簡單的自身版本代替功能,以便更輕松地進行測試,
  2. 我不需要以任何方式更改我的原始代碼(例如,我嘗試過-通過傳遞函數指針有效地進行了更改), mock模塊使我可以對內部對象進行后期編碼訪問。

感謝奧斯丁提出的使用mock建議。 順便說一句,我正在使用Python 2.7,因此使用了PyPI的pip -installable mock

在您的代碼中,您不應該能夠像這樣覆蓋complicated_function 如果嘗試,我會UnboundLocalError: local variable 'complicated_function' referenced before assignment得到UnboundLocalError: local variable 'complicated_function' referenced before assignment

但是,也許是這樣的問題:在您的實際代碼中,您是以其他方式(例如,作為模塊的成員)引用了complicated_function嗎? 然后通過在測試中覆蓋它,就覆蓋了實際的complicated_function ,因此您將無法在其他測試中使用它。

正確的方法是用全局變量覆蓋局部變量,如下所示:

def my_loopy_function(action_function=None):
  if action_function is None:
    action_function = complicated_function
  aggregate_value = 0
    for x in range(10):
      # Use action_function here instead of complicated_function
      aggregate_value = aggregate_value + action_function(x)
    return aggregate_value

暫無
暫無

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

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