簡體   English   中英

為什么在生產類構造函數需要額外參數時unittest.mock會失敗?

[英]Why does unittest.mock fail when the production class constructor takes extra arguments?

我遇到了一個問題,我認為這可能是我正在使用的庫的一個錯誤。 但是,我對python,unittest和unittest.mock庫相當新,所以這可能只是我理解中的漏洞。

在為某些生產代碼添加測試時遇到了錯誤,我生成了一個重現問題的最小樣本:

import unittest
import mock

class noCtorArg:
    def __init__(self):
        pass
    def okFunc(self):
        raise NotImplemented


class withCtorArg:
    def __init__(self,obj):
        pass
    def notOkFunc(self):
        raise NotImplemented
    def okWithArgFunc(self, anArgForMe):
        raise NotImplemented

class BasicTestSuite(unittest.TestCase):
    """Basic test Cases."""

    # passes
    def test_noCtorArg_okFunc(self):
        mockSUT = mock.MagicMock(spec=noCtorArg)
        mockSUT.okFunc()
        mockSUT.assert_has_calls([mock.call.okFunc()])

    # passes
    def test_withCtorArg_okWithArgFuncTest(self):
        mockSUT = mock.MagicMock(spec=withCtorArg)
        mockSUT.okWithArgFunc("testing")
        mockSUT.assert_has_calls([mock.call.okWithArgFunc("testing")])

    # fails
    def test_withCtorArg_doNotOkFuncTest(self):
        mockSUT = mock.MagicMock(spec=withCtorArg)
        mockSUT.notOkFunc()
        mockSUT.assert_has_calls([mock.call.notOkFunc()])


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

我如何運行測試和輸出如下:

E:\work>python -m unittest testCopyFuncWithMock
.F.
======================================================================
FAIL: test_withCtorArg_doNotOkFuncTest (testCopyFuncWithMock.BasicTestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "testCopyFuncWithMock.py", line 38, in test_withCtorArg_doNotOkFuncTest
    mockSUT.assert_has_calls([mock.call.notOkFunc()])
  File "C:\Python27\lib\site-packages\mock\mock.py", line 969, in assert_has_calls
    ), cause)
  File "C:\Python27\lib\site-packages\six.py", line 718, in raise_from
    raise value
AssertionError: Calls not found.
Expected: [call.notOkFunc()]
Actual: [call.notOkFunc()]

----------------------------------------------------------------------
Ran 3 tests in 0.004s

FAILED (failures=1)

我正在使用python 2.7.11,通過pip安裝了模擬版本2.0.0。

對我做錯了什么的建議? 或者這看起來像圖書館中的錯誤?

有趣的是,您選擇執行斷言的方式掩蓋了您的問題。

試試,而不是這個:

mockSUT.assert_has_calls(calls=[mock.call.notOkFunc()])

去做這個:

mockSUT.assert_has_calls(calls=[mock.call.notOkFunc()], any_order=True)

你會看到實際的例外:

TypeError("'obj' parameter lacking default value")

這是因為您嘗試使用具有參數obj且沒有默認值的withCtorArg實例化該類的實例。 如果您曾嘗試直接實例化它,您會看到:

TypeError: __init__() takes exactly 2 arguments (1 given)

但是,由於您讓mock庫處理模擬對象的實例化,因此會發生錯誤 - 並且您會收到TypeError異常。

修改相關課程:

class withCtorArg:
    def __init__(self, obj = None):
        pass
    def notOkFunc(self):
        pass
    def okWithArgFunc(self, anArgForMe):
        pass

並為obj添加默認的None值解決了這個問題。

我不認為我可以明確地解釋為什么會出現這種情況,我仍然懷疑Mock庫中存在一個錯誤,因為問題只發生在被調用函數沒有參數的測試用例上。 感謝advance512指出真正的錯誤被隱藏了!

但是要解決此問題,無需修改生產代碼,我將使用以下方法:

# passes
@mock.patch ('mymodule.noCtorArg')
def test_noCtorArg_okFunc(self, noCtorArgMock):
    mockSUT = noCtorArg.return_value
    mockSUT.okFunc()
    mockSUT.assert_has_calls([mock.call.okFunc()])

# passes
@mock.patch ('mymodule.withCtorArg')
def test_withCtorArg_okWithArgFuncTest(self, withCtorArgMock):
    mockSUT = withCtorArg.return_value
    mockSUT.okWithArgFunc("testing")
    mockSUT.assert_has_calls([mock.call.okWithArgFunc("testing")])

# now passes
@mock.patch ('mymodule.withCtorArg')
def test_withCtorArg_doNotOkFuncTest(self, withCtorArgMock):
    mockSUT = withCtorArg.return_value
    mockSUT.notOkFunc()
    mockSUT.assert_has_calls([mock.call.notOkFunc()], any_order=True)

編輯:

這樣做的一個問題是模擬沒有spec集。 這意味着SUT能夠調用原始類定義中不存在的方法。

另一種方法是將類包裝起來進行模擬:

class withCtorArg:
    def __init__(self,obj):
        pass
    def notOkFunc(self):
        raise NotImplemented
    def okWithArgFunc(self, anArgForMe):
        raise NotImplemented

class wrapped_withCtorArg(withCtorArg):
    def __init__(self):
        super(None)

class BasicTestSuite(unittest.TestCase):
    """Basic test Cases."""

    # now passes
    def test_withCtorArg_doNotOkFuncTest(self):
        mockSUT = mock.MagicMock(spec=wrapped_withCtorArg)
        mockSUT.notOkFunc()
        #mockSUT.doesntExist() #causes the test to fail. "Mock object has no attribute 'doesntExist'"
        assert isinstance (mockSUT, withCtorArg)
        mockSUT.assert_has_calls([mock.call.notOkFunc()], any_order=True)

暫無
暫無

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

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