2016-12-04 2 views
2

Первые две функции display_pane_1 и template_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 x: 'hell mum' должно потерпеть неудачу.

Я пробовал два пути к решению.

Первый вариант - простая копия test_1, заменяющая аргумент lambdademo.template_1 макету lambda. Я не мог найти ничего в руководстве, которое подсказывает, как мне высмеивать выражение, подобное лямбда. Если это в руководстве, пожалуйста, скажите мне, где.

Мой второй вариант следует из более широкого поиска здесь, в разделе «Переполнение стека» и в Интернете. Отсутствие ответных хитов для выражения python unittest, «python lambda unittest», «python expression mock» или «python lambda mock» предположил, что я могу задать неправильный вопрос. Является ли мое предположение, что мне нужно будет издеваться над выражением лямбды?

Я знаю, что простым решением для кодирования было бы сохранить исходный код, но на данный момент меня больше интересует заполнение пробела в моих знаниях.

+1

Зачем совмещать эти функции таким образом? Если вы хотите быть в состоянии фальсифицировать функциональность 'template_1', лучше всего оставить ее выставленной для насмешки. – user2357112

+0

@ пользователь2357112. +1 для опроса мудрости использования лямбда-выражения, когда он нуждается в тестировании, потому что он также является частью A.P.I. для кода.Однако мое любопытство было направлено на более простой вопрос о том, как проверить его, если обстоятельства требуют его использования. Мне кажется, что любой действительный код Python должен быть тестируемым, и программисту необходимо знать, как его проверить. – lemi57ssss

ответ

2

Если выражение лямбда доступно где-то как атрибут класса или модуля, то вы можете издеваться над ним, но это кажется очень маловероятным. Обычно выражение лямбда используется, когда вам не нужна ссылка на функцию. В противном случае вы просто используете регулярную функцию.

Тем не менее, вы можете получить аргументы ко всем вызовам макетного объекта, чтобы вы могли посмотреть на выраженное лямбда-выражение, которое было передано. В примере, подобном тому, который вы дали, самое простое дело было бы просто вызовите выражение лямбда и посмотрите, что он возвращает.

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' 

Если по каким-то причинам вы не хотите, чтобы сделать это, то вы могли бы использовать инспектировать модуль, чтобы посмотреть на лямбда-выражения. Вот пример, который просто сбрасывает строки исходного кода, где определенные функции:

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) 
+0

Ваш интересный и продуманный ответ перемещает лямбда-выражение из тестируемого кода в тест. Похоже, что ваша функция 'foo' действует как прокладка между выражением лямбда и кодом, в котором она используется. Если я применил этот шаблон прокладки к моей исходной функции 'display_pane_2', я бы восполнил три функции:' display_pane_2', прокладку и лямбда-выражение. Это говорит о том, что одна функция действительно неуместна. – lemi57ssss

+1

Я не уверен, что вы подразумеваете под прокладкой, @ lemi57ssss. Я обновил свой ответ, чтобы включить тест вашего исходного кода примера. –

+0

Я использовал термин «прокладка» в его общем смысле спейсера, который не требуется для основной функции компонентов, которые он разделяет. Там есть поддержка некоторой вторичной функции, в данном случае, тестирования. Запись в wikipedia для «shim (computing)» предполагает, что это общее использование превратилось в термин, который не является полезным. https://en.wikipedia.org/wiki/Shim_(computing) Ваше обновление было наиболее освежающим. – lemi57ssss

Смежные вопросы