首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >嘲笑一整类

嘲笑一整类
EN

Stack Overflow用户
提问于 2015-11-11 21:39:28
回答 1查看 2.9K关注 0票数 1

长话短说,我完全能够模拟类方法,当被模拟对象替换的只是那个方法时,但是当我试图用模拟对象替换整个类时,我无法模拟这个方法。

@mock.patch.object成功地模拟了scan方法,但是@mock.patch没有这样做。我在https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch学习过这个例子,但显然我做错了什么。

在这两种情况下,我都在相同的名称空间中模拟词汇表模块(它是由import lexiconsentence_parser中导入的),但是mock_lexicon is lexicon.lexicon检查失败了

代码语言:javascript
复制
#!python
import sys;
sys.path.append('D:\python\lexicon');
import lexicon;

import sentence_parser;
import unittest2 as unittest;
import mock;

class ParserTestCases(unittest.TestCase) :

    def setUp(self) :
        self.Parser = sentence_parser.Parser();

    @mock.patch('lexicon.lexicon')
    def test_categorizedWordsAreAssigned_v1(self, mock_lexicon) :

        print "mock is lexicon:";
        print mock_lexicon is lexicon.lexicon + "\n";

        instance = mock_lexicon.return_value;
        instance.scan.return_value = "anything";    

        self.Parser.categorize_words_in_sentence("sentence");
        instance.scan.assert_called_once_with("sentence");

    @mock.patch.object(lexicon.lexicon, 'scan')
    def test_categorizedWordsAreAssigned_v2(self, mock_scan) :

        mock_scan.return_value = "anything";    

        self.Parser.categorize_words_in_sentence("sentence");
        mock_scan.assert_called_once_with("sentence");

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

产出:

代码语言:javascript
复制
mock is lexicon:
False

======================================================================
FAIL: test_categorizedWordsAreAssigned_v1 (__main__.ParserTestCases)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\python\get_img\getImage_env\lib\site-packages\mock\mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "./test_sentence_parser.py", line 26, in test_categorizedWordsAreAssigned_v1
    instance.scan.assert_called_once_with("sentence");
  File "D:\python\get_img\getImage_env\lib\site-packages\mock\mock.py", line 947, in assert_called_once_with
    raise AssertionError(msg)
AssertionError: Expected 'scan' to be called once. Called 0 times.

----------------------------------------------------------------------
Ran 2 tests in 0.009s

FAILED (failures=1)

编辑:

为了澄清,Parser的定义如下

代码语言:javascript
复制
#!python

import sys;
sys.path.append('D:\python\lexicon');
import lexicon;

class Parser(object) :

    my_lexicon = lexicon.lexicon()

    def __init__(self) :
        self.categorized_words = ['test'];

    def categorize_words_in_sentence(self, sentence) :
        self.categorized_words = self.my_lexicon.scan(sentence);


if (__name__ == '__main__') :
    instance = Parser();
    instance.categorize_words_in_sentence("bear");
    print instance.categorized_words;
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-11-12 20:47:34

这里真正相关的是categorize_words_in_sentence Parser的方法如何使用lexicon。但首先,我们应该消除噪音:

代码语言:javascript
复制
print mock_lexicon is lexicon.lexicon + "\n"

是什么会把我们引向错误的方向:尝试用

代码语言:javascript
复制
self.assertIs(mock_lexicon, lexicon.lexicon)

您将了解到,您正在打印False,因为mock_lexicon不是lexicon.lexicon + "\n",而是lexicon.lexicon

现在我无法告诉您为什么第一个测试不起作用,因为答案是在categorize_words_in_sentence方法中,或者更可能在sentence_parser模块中,在那里我可以猜到

代码语言:javascript
复制
from lexicon import lexicon

在这两种情况下,请查看补丁在哪里?文档,这些文档可以启发您了解什么是原因,哪些是您真正需要修补的地方。

第二个版本之所以有效,仅仅是因为您正在修补对象,而不是引用(这应该是不同的)。

最后,更简洁和一般性的版本可以是:

代码语言:javascript
复制
@mock.patch('lexicon.lexicon.scan', return_value="anything")
def test_categorizedWordsAreAssigned_v3(self, mock_scan) :
    self.Parser.categorize_words_in_sentence("sentence")
    mock_scan.assert_called_once_with("sentence")

还有一件事:删除unittest2,至少您没有使用python2.4,而且您对支持的统一特性很感兴趣。

编辑

现在,我可以停下来猜测一下,并指出为什么第一个版本不能工作,而且永远不会起作用:

代码语言:javascript
复制
class Parser(object) :
    my_lexicon = lexicon.lexicon()

Parser.my_lexicon属性是在加载时计算的。这意味着当您导入sentence_parser时,将创建一个lexicon,并将引用关联到Parser.my_lexicon。当您修补lexicon.lexicon时,您将此引用保持不变,解析器对象仍然使用导入时创建的原始引用。

您可以做的是通过以下方法修补Parser类中的引用

代码语言:javascript
复制
@patch("sentence_parser.Parser.my_lexicon")

您可以使用create_autospect,如果您想要给您的模拟lexicon的签名。

代码语言:javascript
复制
@patch("sentence_parser.Parser.my_lexicon", create_autospec("lexicon.lexicon", instance=True))
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33660332

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档