【问题标题】:Difficulty mocking classes using python 'mock' (django)使用 python 'mock' (django) 难以模拟类
【发布时间】:2014-09-11 09:38:10
【问题描述】:

我正在使用 python 的“模拟”模块来模拟 django 项目中的类和函数。 我的项目结构是:

Project name --> 'hello'
               App1 ----> hello
               App2 ----> hello_world
               App3 ----> bye

'hello' 仅包含 tests.pysettings.py。 'hello_world' 包含视图文件 'greetings.py',如下所示:

from django.shortcuts import render
from django.http import HttpRequest,HttpResponse
from bye import views

# Create your views here.                                                                                                                                                                                   

def greet(request):
    views.saybye()
    gb_class = views.goodbye()

    print gb_class.saygoodbye()
    print 'greet called'

    return HttpResponse('hello world',content_type='application/html')

“再见”包含“views.py”,其中包含:

from django.shortcuts import render 
from django.http import HttpRequest

# Create your views here.

def saybye():
    print "goodbye world"
    return

class goodbye:
    def __init__(self):
        print "goodbye's init called"
        return

    def saygoodbye(self):
        return "goodbye.saygoodbye called"

现在,我的“tests.py”是:

from unittest import TestCase

import mock
from mock import patch

from hello_world import greetings
import bye 

from django.test.client import RequestFactory


class TestBasic(TestCase):
    def setUp(self):
        self.var = 'abc'
        self.factory = RequestFactory()

    @patch('bye.views.goodbye')
    def test_greeting(self,mocksaybye):
        assert mocksaybye is bye.views.goodbye
        mocksaybye.saygoodbye = mock.MagicMock(return_value="mocked goodbye called")

        bye.views.goodbye()
        print mocksaybye.saygoodbye()

        assert mocksaybye.called
        assert mocksaybye.saygoodbye.called

        req = self.factory.get('/sayhello/')
        greetings.greet(req)

我在运行“python manage.py test”时得到以下输出:

mocked goodbye called
goodbye world
<MagicMock name='goodbye().saygoodbye()' id='60566864'>
greet called

我希望输出的第 3 行是:"mocked goodbye called" 据我了解,mocksaybye 类将模拟 goodbye 类的 saygoodbye 函数并返回自定义输出 mocked goodbye called

但是,这不会发生。为什么会这样?另外,我应该怎么做才能得到这个期望的输出?

【问题讨论】:

    标签: python django unit-testing mocking patch


    【解决方案1】:

    您需要使用side_effect 方法,而不是return_value。还有@patch.object而不是@patch

    所以代替这段代码:

    @patch('bye.views.goodbye')
    def test_greeting(self,mocksaybye):
        # ...
        mocksaybye.saygoodbye = mock.MagicMock(return_value="mocked goodbye called")
        # ...
    

    使用这个(未测试):

    @patch.object('bye.views.goodbye', 'saygoodbye')
    def test_greeting(self,mocksaybye):
        # ...
        mocksaybye.side_effect = lambda: "mocked goodbye called"
        # ...
    

    【讨论】:

    • @nomad,您是否尝试过答案中的第二种解决方案?
    • 这个答案实际上与return_value 相同。我认为问题在于您需要模拟greetings.views.goodbye
    • 也可能出现问题:goodbye 是一个老式类,它不是继承自object
    • @SimeonVisser 仍然不起作用。输出还是一样的。
    • @stalk 上述解决方案均无效。输出不受影响。
    猜你喜欢
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多