我正在使用Reddit机器人来学习python中的TDD。
我有一个类似于以下类的模块:
from praw import Reddit
class Bot():
def __init__(self):
self.reddit = Reddit(user_agent='myBot')
self.reddit.login('fake', 'fakePassword')
在我的测试套件中,我有一个像这样的设置方法:
@patch('bot.bot.Reddit.login')
def setUp(self, mocked_reddit):
self.mocked_reddit = mocked_reddit
self.subject = Bot()
..和这样的测试:
def should_call_reddit_login_when_initialized_test(self):
self.assertTrue(self.mocked_reddit.assert_called_with('fake', 'fakePassword'))
好像我的补丁只是部分工作。它实际上并没有调用好的Reddit API。然而,断言总是错误的。
line 22 in should_call_reddit_login_when_initialized_test
self.assertTrue(self.mocked_reddit.assert_called_with('fake', 'fakePassword'))
AssertionError: None is not true
理想情况下,我可以模拟整个Reddit类,并断言以后使用预期参数调用方法。我怎么能做到这一点?
答案 0 :(得分:4)
assert_called_with
是断言。只要没有触发,即提出AssertionError
例外,那么你就行了。您无需检查其返回值,该值始终为None
。
答案 1 :(得分:2)
你问两件事:
Reddit
对于 1 @wim的回答是正确的,并告诉您具体如何修复它:用以下代码替换您的测试行:
self.mocked_reddit.assert_called_with('fake', 'fakePassword')
断言失败时, assert_*
模拟调用已经引发异常。
要照顾 2 ,您应该修改'bot.bot.Reddit'
,并考虑您的对象将是您模拟的return_value
。在这种情况下,我强烈建议您使用autospec=True
来保留Reddit
完整签名,请查看Autospeccing了解更多详情。
在这种情况下,您的测试成为:
@patch('bot.bot.Reddit', autospec=True)
def setUp(self, mocked_reddit_class):
self.mocked_reddit_class = mocked_reddit_class
self.mocked_reddit = mocked_reddit_class.return_value
self.subject = Bot()
def should_call_reddit_login_when_initialized_test(self):
self.mocked_reddit.login.assert_called_with('fake', 'fakePassword')
在这种情况下,您应该注意使用self.mocked_reddit
来检查对象方法,使用self.mocked_reddit_class
来检查静态和类方法。举个简单的例子:
import unittest
from unittest.mock import patch
class A():
def b(self, a, b):
pass
@classmethod
def c(cls,a,b):
pass
@staticmethod
def d(a,b):
pass
def ab(a,b):
return A().b(a,b)
def ac(a,b):
return A.c(a,b)
def ad(a,b):
return A.d(a,b)
class MyTestCase(unittest.TestCase):
@patch(__name__+".A", autospec=True)
def test_something(self,mock_a):
ab(1,2)
mock_a.return_value.b.assert_called_with(1,2)
ac(1,2)
self.assertFalse(mock_a.return_value.c.called)
mock_a.c.assert_called_with(1,2)
ad(1,2)
self.assertFalse(mock_a.return_value.d.called)
mock_a.d.assert_called_with(1,2)