2010-09-28 62 views
23

我想測試發送的信號,它是offering_args。在表單提交後立即在contact_question_create視圖內觸發的信號。正確的方式來測試Django信號

我的TestCase是一樣的東西:

def test_form_should_post_proper_data_via_signal(self): 
     form_data = {'name': 'Jan Nowak'} 
     signals.question_posted.send(sender='test', form_data=form_data) 
     @receiver(signals.question_posted, sender='test') 
     def question_posted_listener(sender, form_data): 
      self.name = form_data['name'] 
     eq_(self.name, 'Jan Nowak') 

這是測試這個信號的正確方法?任何更好的想法?

+0

相關:http://stackoverflow.com/questions/13112302/how-do-i-mock-a-django-signal-handler – 2014-06-13 20:41:13

回答

3

我自己解決了這個問題。我認爲最好的解決方案如下:

def test_form_should_post_proper_data_via_signal(self): 
     # define the local listener 
     def question_posted_listener(sender, form_data, **kwargs): 
      self.name = form_data['name'] 

     # prepare fake data 
     form_data = {'name': 'Jan Nowak'} 

     # connect & send the signal 
     signals.question_posted.connect(question_posted_listener, sender='test') 
     signals.question_posted.send(sender='test', form_data=form_data) 

     # check results 
     eq_(self.name, 'Jan Nowak') 
+4

這將不會失敗,如果一個信號是兩次或更多的emited。 – jpic 2012-10-06 10:47:56

1

爲什麼你測試你的框架? Django已經爲信號調度器進行了單元測試。如果你不相信你的框架是好的,那就把單元測試附加到你的測試運行器上。

+3

請注意,他並未測試Django框架如何表示邏輯行爲,但實際測試他的代碼何時以及如何觸發Django信號。 – 2015-05-12 17:29:21

4

這樣做的目的不是測試底層的信號機制,而是一個重要的單元測試,以確保您的方法應該發出的任何信號實際上都是用適當的參數發出的。在這種情況下,它看起來有點微不足道,因爲它是一個內部django信號,但想象一下如果您編寫了發送定製信號的方法。

6

您需要:

  • 聲明信號與正確的參數被emited,
  • 特定次數,在適當的順序

您可以使用mock_django應用程序,它提供了mock for signals

例子:

from mock import call 


def test_install_dependency(self): 
    with mock_signal_receiver(post_app_install) as install_receiver: 
     self.env.install(self.music_app) 
     self.assertEqual(install_receiver.call_args_list, [ 
      call(signal=post_app_install, sender=self.env, 
       app=self.ukulele_app), 
      call(signal=post_app_install, sender=self.env, 
       app=self.music_app), 
     ]) 
+0

請注意,版本1.6.5的mock_django不支持Django 1.5或更高版本。 (在撰寫本文時,1.6.5是最新的標記版本,並且是PyPI中的版本。) – 2013-12-20 09:12:27

+1

@jpic你能否請求添加「來自模擬導入電話」的行,因爲它不明顯? – syabro 2014-12-26 05:31:05

+1

我已經發布了使用模擬庫而不是mock_django的更新。見下文。 – bbengfort 2015-02-16 13:15:00

11

我必須使用mock庫,這是目前在Python 3 unittest.mock標準庫的一部分的替代建議(如果你使用Python 2,你必須pip install mock )。

try: 
    from unittest.mock import MagicMock 
except ImportError: 
    from mock import MagicMock 

def test_form_should_post_proper_data_via_signal(self): 
    """ 
    Assert signal is sent with proper arguments 
    """ 

    # Create handler 
    handler = MagicMock() 
    signals.question_posted.connect(handler, sender='test') 

    # Post the form or do what it takes to send the signal 
    signals.question_posted.send(sender='test', form_data=form_data) 

    # Assert the signal was called only once with the args 
    handler.assert_called_once_with(signal=signals.question_posted, form_data=form_data) 

建議的重要組成部分是嘲笑接收器,然後測試您的信號是否被髮送到接收器,並呼籲只有一次。這很好,特別是如果你有自定義信號,或者你已經編寫了發送信號的方法,並且你希望在單元測試中確保它們正在發送。

+0

AttributeError:'function'對象沒有屬性'connect' – chefarov 2017-06-27 20:02:51

20

最簡單的做法是你在2015年問:

from unittest.mock import patch 

@patch('full.path.to.signals.question_posted.send') 
def test_question_posted_signal_triggered(self, mock): 
    form = YourForm() 
    form.cleaned_data = {'name': 'Jan Nowak'} 
    form.save() 

    # Check that your signal was called. 
    self.assertTrue(mock.called) 

    # Check that your signal was called only once. 
    self.assertEqual(mock.call_count, 1) 

    # Do whatever else, like actually checking if your signal logic did well. 

有了這樣的,你只是測試你的信號是正確的觸發。

+2

您好José,我無法得到它的工作 - 我認爲這可能是與dispatch_uid有關。我最終使用了'with patch('xyz')作爲mocked_handler'方法。 – stephendwolff 2015-10-22 05:44:34

+2

我認爲更準確的是不僅會調用事實,而且會調用參數,使用mock.assert_called_once_with – 2016-02-17 09:49:04