2013-12-23 5 views
1

Итак, вот что я пытаюсь выяснить. У меня есть метод, который запускается post_save для этой модели «История». Работает отлично. Что мне нужно сделать, так это выяснить, как издеваться над тестом, так что я могу подделать вызов и сделать утверждения по моим возвращениям. Я думаю, что мне нужно как-то исправлять его, но я пробовал пару разных способов без особого успеха. Лучше всего я могу получить экземпляр объекта, но он игнорирует значения, которые я передаю.Издевательство над методом django с использованием сигнала post_save

Я прокомментировал в своем тесте, где мое замешательство. Любая помощь приветствуется.

Вот мой тест:

from django.test import TestCase 
from django.test.client import Client 
from marketing.blog.models import Post, Tag 
from unittest.mock import patch, Mock 

class BlogTestCase(TestCase): 
    fixtures = [ 
     'auth-test.json', 
     'blog-test.json', 
    ] 

    def setUp(self): 
     self.client = Client() 

    def test_list(self): 
     # verify that we can load the list page 
     r = self.client.get('/blog/') 
     self.assertEqual(r.status_code, 200) 
     self.assertContains(r, "<h1>The Latest from Our Blog</h1>") 
     self.assertContains(r, '<a href="/blog/javascript-date-formatting/">Simple JavaScript Date Formatting</a>') 
     self.assertContains(r, 'Page 1 of 2') 

     # loading a page out of range should redirect to last page 
     r = self.client.get('/blog/5/', follow=True) 
     self.assertEqual(r.redirect_chain, [ 
      ('http://testserver/blog/2/', 302) 
     ]) 
     self.assertContains(r, 'Page 2 of 2') 

     # verify that unpublished posts are not displayed 
     with patch('requests') as mock_requests: 
      # my futile attempt at mocking. 
      # creates <MagicMock> object but not able to call return_values 
      mock_requests.post.return_value = mock_response = Mock() 

      # this doesn't get to the magic mock object. Why? 
      mock_response.status_code = 201 

      p = Post.objects.get(id=5) 
      p.published = False 
      # post_save signal runs here and requests is called. 
      # Needs to be mocked. 
      p.save() 

      r = self.client.get('/blog/') 
      self.assertNotContains(r, '<a href="/blog/javascript-date-formatting/">Simple JavaScript Date Formatting</a>') 

Вот модель:

from django.db import models 
from django.conf import settings 
from django.db.models import signals 
import requests 

def update_console(sender, instance, raw, created, **kwargs): 
    # ignoring raw so that test fixture data can load without 
    # hitting this method. 
    if not raw: 
     update = instance 

     json_obj = { 
      'author': { 
       'alias': 'the_dude', 
       'token': 'the_dude' 
      }, 
      'text': update.description, 
     } 

     headers = {'content-type': 'application/json'} 

     path = 'http://testserver.com:80/content/add/' 
     request = requests(path, 'POST', 
      json_obj, headers=headers, 
      ) 
     if request.status_code < 299: 
      story_id = request.json().get('id') 
      if story_id: 
       # disconnect and reconnect signal so 
       # we don't enter recursion-land 
       signals.post_save.disconnect(
        update_console, 
        sender = Story,) 
       update.story_id = story_id 
       update.save() 
       signals.post_save.connect(
        update_console, 
        sender = Story,) 
     else: 
      raise AttributeError('Error Saving to console, '+ request.text) 

class Story(models.Model): 
    """Lets tell a story""" 
    story_id = models.CharField(
     blank=True, 
     max_length=10, 
     help_text="This maps to the id of the post" 
    ) 
    slug = models.SlugField(
     unique=True, 
     help_text="This is used in URL and in code references.", 
    ) 
    description = models.TextField(
     help_text='2-3 short paragraphs about the story.', 
    ) 

    def __str__(self): 
     return self.short_headline 

# add/update this record as a custom update in console 
signals.post_save.connect(update_console, sender = Story) 
+0

Аналогичный вопрос: http://stackoverflow.com/questions/12317255/python-mock-library-patching-classes-while-unit-testing –

ответ

2

Вам нужно пропатчить requests в модуле, где он фактически используется, т.е.

with patch('path.to.your.models.requests') as mock_requests: 
    mock_requests.return_value.status_code = 200 
    mock_requests.return_value.json.return_value = {'id': story_id'} 
    ... 

документация предлагает более подробные разъяснения по where to patch:

патч работает (временно), изменяя объект, с которым указывает имя с другим. Может быть много имен, указывающих на любой отдельный объект, поэтому для исправления для работы вы должны убедиться, что вы исправляете имя, используемое тестируемой системой.

Основным принципом является то, что вы исправляете, где объект просматривается, что не обязательно совпадает с местом, где оно определено.

Здесь вам нужно пропатчить имя requests внутри models модуля, следовательно, необходимость обеспечения его полного пути.

+0

Привет, Николас, спасибо за ваш ответ ... Я пробовал исправить запрашивает модуль, где я его использую, и получаю от него магический макет-объект; но по какой-то причине я не могу получить значения, которые я пытаюсь высмеять из моего теста. Например, после исправления ('my.model.requests') как mock_requests, я объявляю mock_requests.status_code = 201. Когда тест запускается, я не могу получить возвращаемый код состояния, просто экземпляр магии. например: (Pdb) request.status_code <имя_магистрального_значения = 'request.request(). status_code' id = '4342421584'> – uxtx

+0

@uxtx Как вы вызываете 'request = requests (...) 'вам нужно исправить возвращаемое значение. Я соответствующим образом обновил свой пример. –

+0

Николас, спасибо за разъяснение. Это сделал трюк. – uxtx

Смежные вопросы