是否可以模拟lambda表达式?

时间:2016-12-04 15:44:59

标签: python unit-testing lambda

前两个函数display_pane_1template_1很容易测试 在方法test_1中。我想将这两个函数重构为单个函数display_pane_2

lambdademo.py:

def display_pane_1():
    display_register(template_1)


def template_1():
    return 'hello mum'


def display_pane_2():
    display_register(lambda: 'hello mum')


def display_register(template):
    print(template())

test_lambdademo.py

import unittest
import unittest.mock as mock

import lambdademo


class TestLambda1(unittest.TestCase):
    def setUp(self):
        p = mock.patch('lambdademo.display_register')
        self.mock_display_register = p.start()
        self.addCleanup(p.stop)

    def test_1(self):
        lambdademo.display_pane_1()
        self.mock_display_register.assert_called_with(lambdademo.template_1)

    def test_2(self):
        lambdademo.display_pane_2()
        self.mock_display_register.assert_called_with('????????')

你能帮我写一个display_pane_2的有效测试吗?我想测试完整的lambda表达式,即lambda x: 'hell mum'应该失败。

我尝试了两种解决方案。

第一个选项是test_1的简单副本,用模拟lambdademo.template_1替换lambda的参数。我无法在手册中找到任何建议我如何模拟像lambda这样的表达式的内容。 如果它在手册中,请告诉我在哪里。

我的第二个选项是在Stack Overflow上进行更广泛的搜索,然后是在Internet上。缺乏对“python表达单元测试”的响应性命中, ' python lambda unittest',' python expression mock',或' python lambda mock' 建议我可能会问错误的问题。我的假设是我需要模拟lambda表达式错误吗?

我知道一个简单的编码解决方案就是保留原始代码,但在这一点上,我更有兴趣填补我的知识空白。

1 个答案:

答案 0 :(得分:2)

如果lambda表达式可以像某个类或模块的属性那样访问,那么你可以嘲笑它,但这似乎不太可能。通常,当您不需要对函数的引用时,将使用lambda表达式。否则,您只需使用常规功能。

但是,您可以检索模拟对象上所有调用的参数,这样您就可以查看传入的lambda表达式。在一个例子中,您提供的最简单的方法就是调用lambda表达式并查看它返回的内容。

from mock import patch

def foo(bar):
    return bar()

def baz():
    return 42

print foo(baz)

with patch('__main__.foo') as mock_foo:
    print foo(baz)
    print foo(lambda: 'six by nine')

    assert mock_foo.call_args_list[0][0][0]() == 42
    assert mock_foo.call_args_list[1][0][0]() == 'six by nine'

如果由于某种原因你不想这样做,那么你可以使用inspect模块来查看lambda表达式。这里只是转储定义函数的源代码行的示例:

from inspect import getsource
from mock import patch

def foo(bar):
    return bar()

def baz():
    return 42

print foo(baz)

with patch('__main__.foo') as mock_foo:
    print foo(baz)
    print foo(lambda: 'six by nine')
    print mock_foo.call_args_list
    for call_args in mock_foo.call_args_list:
        print '---'
        print getsource(call_args[0][0])

结果:

42
<MagicMock name='foo()' id='140595519812048'>
<MagicMock name='foo()' id='140595519812048'>
[call(<function baz at 0x7fdef208fc08>),
 call(<function <lambda> at 0x7fdef208fe60>)]
---
def baz():
    return 42

---
    print foo(lambda: 'six by nine')

以下是您的示例代码传递的测试版本。它测试两种方式:调用模板并检查模板的来源。

# test_lambdademo.py

from inspect import getsource
import unittest
import unittest.mock as mock

import lambdademo


class TestLambda1(unittest.TestCase):
    def setUp(self):
        p = mock.patch('lambdademo.display_register')
        self.mock_display_register = p.start()
        self.addCleanup(p.stop)

    def test_1(self):
        lambdademo.display_pane_1()
        self.mock_display_register.assert_called_with(lambdademo.template_1)

    def test_2(self):
        lambdademo.display_pane_2()
        template = self.mock_display_register.call_args[0][0]
        template_content = template()
        template_source = getsource(template)

        self.assertEqual('hello mum', template_content)
        self.assertIn('hello mum', template_source)