【问题标题】:Mock inner methods Python2模拟内部方法 Python2
【发布时间】:2020-01-21 15:31:05
【问题描述】:

我是新手,我真的很挣扎。主要在文档和大多数 SO 页面中,它显示了如何获取模拟 result_value,但我想检查我从方法中获得的值是否正确,而不是 result_value 的值。示例如下:

#!/usr/bin/env python

class Example:

    def one(self):
        return 1

    def two(self, one):
        print(one + 1) # basically any void method, ex: result = one + 1 and check result value if correct

    def main(self):
        self.two(self.one())

if __name__ == '__main__':
    e = Example()
    e.main()

测试:

#!/usr/bin/env python

import unittest
import example
from mock import patch

class Example(unittest.TestCase):

    def test_one(self):
        self.assertEqual(1, et.one())

    def test_two(self):
        with patch('example.Example.two'):
            self.assertEqual(2, et.two(et.one())) # ..the part I'm stuck
                                                  # whick ofc throws AssertionError: 2 != <MagicMock name='two()' id='blablabla'>

    def test_main(self):
        # unknown part..

if __name__ == '__main__':
    et = example.Example()
    unittest.main()

如何用unittest实现void方法检查?

更新:

所以我在 chepner 的帮助下找到了打印:

def test_twoi3(self):
        mock_print = MagicMock()
        with patch('sys.stdout', mock_print):
            print(2)
            expected = call.write('2')
            self.assertEqual(mock_print.mock_calls[0], expected)

对于main,我不太确定这是否是一个好的解决方案...:

def test_main(self):
        with patch ('example.Example.main') as m:
            et.main(et.two(1))
        m.assert_called_with(et.two(1))

但我不想通过传递方法和值来检查,而是main 是否调用其他两个方法。如何做到这一点?

【问题讨论】:

  • 您需要捕获标准输出,而不是检查其返回值。模拟在这里并不合适,因为模拟取代了身体,消除了副作用。你不能模拟你想测试的东西。
  • @chepner 好的,如果方法已被调用并获取它们的值(不是 return_value),如何测试main
  • 您可以模拟 print,并检查它是否以预期值被调用,而不是实际写入标准输出。
  • 或使用contextlib.redirect_stdout 将标准输出捕获到您可以检查其内容的StringIO 对象。
  • @chepner 与print 结果为None(代码:with patch('__builtin__.print', mock_print): self.assertEqual(2, et.two(1))

标签: python mocking python-2.6


【解决方案1】:

你不需要模拟任何东西(直接,反正);您想要捕获标准输出并验证它是否符合您的期望。

from contextlib import redirect_stdout
from io import StringIO

def test_two(self):
    stdout = StringIO()

    with redirect_stdout(stdout):
        et.two(et.one())

    self.assertEqual(stdout.getvalue(), "2\n")

或者,您可以模拟print 并检查它是否被调用并带有预期的参数。

def test_two(self):
    with patch('__builtin__.print') as p:
        et.two(et.one())

    p.assert_called_with(2)

【讨论】:

  • 第二个解决方案是否可以通过传递.._with(self.et.two(self.et.one) 和修补example.Example.main 来测试main
  • 第二个将在with 语句的主体中简单地调用et.main() 而不是et.two(et.one());补丁本身不会改变。
  • 顺便说一句,最好重写setUp 以使et 成为测试用例的属性,这样您就可以为每个方法获得一个新鲜的对象,而不是依赖于共享全球价值。
  • 在我的更新中,我主要测试调用et.main(),但是如何检查是否调用了self.two(self.one)assert_called_with()(空)不是我认为的检查方式
【解决方案2】:

我已经弄清楚如何测试是否调用了主要方法。测试如下:

#!/usr/bin/env python

import unittest
import example
from mock import patch, MagicMock, call

class Example(unittest.TestCase):

    def setUp(self):
        self.et = example.Example()

    def test_one(self):
        self.assertEqual(1, self.et.one())

    def test_two(self):
        mock_print = MagicMock()
        with patch('sys.stdout', mock_print):
            print(2)
            expected = call.write('2')
            self.assertEqual(mock_print.mock_calls[0], expected)

    def test_main(self):
        self.et.two = MagicMock(side_effect=self.et.two)
        self.et.one = MagicMock(side_effect=self.et.one)

        self.et.main()

        self.et.one.assert_called()
        self.et.two.assert_called()

        self.et.one.__str__ = self.et.one
        self.assertEqual(1, int(self.et.one))

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

在模拟 main(所有这些)中的方法并调用 main 方法时,onetwo 已成功调用。对于one,您可以使用__str__ 返回值

【讨论】:

    猜你喜欢
    • 2020-04-04
    • 1970-01-01
    • 2022-12-09
    • 2015-12-18
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多