2015-03-19 43 views
1

我正在使用Reddit bot來學習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類,並斷言稍後使用期望的參數調用方法。我怎樣才能做到這一點?

+2

你*需要*引用外部庫,當執行* unit *測試的事實表明設計缺陷。你應該真的考慮改變你的代碼,以便單元測試真的可以是沒有副作用的單元測試。 – 2015-03-19 04:35:39

+0

我試圖嘲笑它,所以它實際上並沒有被調用。我需要驗證它是否在某個時刻被調用,但我不需要測試調用實際的Reddit api。 – ZeroDivide 2015-03-19 11:44:45

回答

2

你問兩個不同的東西:

  1. 爲什麼我的斷言不工作
  2. 我如何可以模擬整個Reddit

對於 @wim答案是正確的,並告訴給你到底如何解決它:用你的測試線代替:

self.mocked_reddit.assert_called_with('fake', 'fakePassword') 

assert_*當斷言失敗時,模擬調用已經引發異常。

要利用照顧你應該修補'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) 
4

assert_called_with該斷言。只要沒有觸發,即提升AssertionError例外,那麼你沒問題。您無需檢查其返回值,該值始終爲None

+0

我如何在我的設置方法中修補整個Reddit對象? – ZeroDivide 2015-03-19 04:25:08

相關問題