【问题标题】:How to use Python mocking in a unit test如何在单元测试中使用 Python 模拟
【发布时间】:2015-02-11 16:47:23
【问题描述】:

大多数关于 Python 模拟的建议都包含在单元测试框架之外的简短 sn-ps 中。这个工作发现,我正在尝试遵循这个建议,但是一旦我将它嵌入到适当的单元测试中,它就不会成功。例如,这段代码在末尾的注释中产生输出:

# foo.py
def some_fn():
    return 'some_fn'

class Foo( object ):
    def method_1( self ):
        return some_fn()

# bar.py (depends on foo.py)
import foo
class Bar( object ):
    def method_2( self ):
        tmp = foo.Foo()
        return tmp.method_1()

# test.py (tests bar.py)
import unittest
import bar
from mock import patch

class Test( unittest.TestCase ):
    def setUp( self ):
        pass
    def tearDown( self ):
        pass

    @patch( 'foo.some_fn' )
    def test_bar( self, mock_some_fn ):
        mock_some_fn.return_value = 'test-val-1'
        tmp = bar.Bar()
        print tmp.method_2()
        self.assertEqual( tmp.method_2(), 'test-val-1' )  # line 32
        mock_some_fn.return_value = 'test-val-2'
        self.assertEqual( tmp.method_2(), 'test-val-2' )

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

我在 PyDev 中运行并查看:

Finding files... done.
Importing test modules ... done.

some_fn
======================================================================
FAIL: test_bar (test.foo.all.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/mock.py", line 1201, in patched
    return func(*args, **keywargs)
  File "/home/russ/dev/workspace/python-mocking/test/foo/all.py", line 32, in test_bar
    self.assertEqual( tmp.method_2(), 'test-val-1' )
AssertionError: 'some_fn' != 'test-val-1'

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (failures=1)

删除单元测试框架,这段代码运行良好(这里,只是整个文件的 test.py 部分):

...
# test.py (tests bar.py)
import bar
from mock import patch

@patch( 'foo.some_fn' )
def test_bar( mock_some_fn ):
  mock_some_fn.return_value = 'test-val-1'
  tmp = bar.Bar()
  print tmp.method_2()
  assert tmp.method_2() == 'test-val-1'
  mock_some_fn.return_value = 'test-val-2'
  assert tmp.method_2() == 'test-val-2'

运行时成功生成:

~/dev/workspace/python-mocking/test/foo $ python
Python 2.7.5 (default, Nov  3 2014, 14:26:24) 
...
>>> import all0
>>> all0.test_bar()
test-val-1

我还必须做些什么才能使其在单元测试框架中运行?

【问题讨论】:

  • 抱歉,我无法重现您的问题。尝试使用self.assertEqual(tmp.method_2(), 'test-val-1') 而不是assert .... 看看有什么区别。据我所见,它应该可以完美运行....我在很多 python 版本(2.7、3.2 和 3.4)中都非常频繁地使用 mockunittesting,而没有任何此类问题。
  • 谢谢。正如您所要求的那样,我正在修改我的单元测试代码,并且我还进行了其他小的更改以使问题更清晰。我有几个使用从 Googleland 收集的不同代码 sn-ps 来解决此问题的示例。我用 Python 写了 3 个月。我是一个 Java 人,习惯于在单元测试中广泛使用模拟,因此试图在 Python 中得到它。
  • 你也可以更新 pyDev 输出吗?它仍然引用旧代码,因为在堆栈跟踪中我读到了assert tmp.method_2() == 'test-val-1'
  • 我最好的猜测是关于 Eclipse/PyDev:你能尝试在控制台上通过python test.py 调用 unittest 版本吗?我打赌它会奏效。
  • 不是来自 python 控制台,而是来自你的命令行 shell。 (我假设您在 Windows 上)进入 test.py 所在的同一目录并键入 python.exe test.py... 如果不起作用,则将 python.exe 替换为 python.exe 的完整路径。顺便说一句,我想指出你应该错过了什么......没有办法通过剪切和粘贴你的例子来重现它。

标签: python python-2.7 python-unittest python-mock


【解决方案1】:

对于我这个 Python 和 PyDev 新手来说,答案是这是一个 PyDev 问题。 PyDev 似乎对如何设置项目的单元测试非常敏感。我通过将一个与此完全相同的新项目(包括单独的文件)组合在一起,成功地使这段代码工作。

python-mocking
+-- mocking_example
    +-- test
    |   +-- __init__.py
    |   `-- test.py
    +-- __init__.py
    +-- bar.py
    `-- foo.py

可能值得注意的是,上面的结构使得在 test.py 中,bar 必须这样导入:

import mocking_example.bar

并以这种方式消费,即:

tmp = mocking_example.bar.Bar()

【讨论】:

  • 我认为您的问题在于项目的 python 路径配置:如果您将 mocking_example 添加到您的 python 路径中,您可以毫无问题地访问它。
  • 是的,谢谢,我明白了。我不想影响我的 PyDev 项目的可移植性,并且拒绝这样做。这回答了一个密切相关的问题:stackoverflow.com/questions/9249995/…
  • 我看到你是一个 java 开发者,所以 Eclipse 是你的家,但我想推荐尝试 PyCharm... 是非常棒的工具!
猜你喜欢
  • 2014-01-29
  • 2022-11-29
  • 2017-06-14
  • 2017-07-03
  • 2021-12-02
  • 1970-01-01
  • 2014-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多