【问题标题】:objects are swapped when running tests in django在 django 中运行测试时交换对象
【发布时间】:2021-12-26 22:43:45
【问题描述】:

如果我解释有误,我想立即道歉。我是通过谷歌翻译写这篇文章的

Django 在一次测试后显示测试错误。 测试成功一次,然后失败。 如果我什至不改变任何东西,那么一个仍然通过,另一个没有。

测试

def create_category():
    return Category.objects.create(category_title='Category title', slug='category-title')


def create_news(category, title, text='news text', pub_date=timezone.now()):
    return News.objects.create(category=category, image=None, title=title,
                               text=text, pub_date=pub_date)


class HomePageTestCase(TestCase):
    def test_no_news(self):
        response = self.client.get(reverse('news:home'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'News not found')
        self.assertQuerysetEqual(response.context['last_20_news'], [])

    def test_one_news(self):
        category = create_category()
        news = create_news(category, 'News title')
        response = self.client.get(reverse('news:home'))
        self.assertQuerysetEqual(response.context['last_20_news'], ['<News: News title>'])

    def test_multiple_news(self):
        category = create_category()
        news_1 = create_news(category, 'News title 1')
        news_2 = create_news(category, 'News title 2')
        response = self.client.get(reverse('news:home'))
        self.assertQuerysetEqual(response.context['last_20_news'], ['<News: News title 2>', '<News: News title 1>'])


class CategoryPageTestCase(TestCase):
    def test_no_news_from_category(self):
        category = create_category()
        response = self.client.get(category.get_absolute_url())
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'News not found')
        self.assertQuerysetEqual(response.context['news_from_category'], [])

    def test_one_news_from_category(self):
        category = create_category()
        news = create_news(category, 'News title')
        response = self.client.get(category.get_absolute_url())
        self.assertQuerysetEqual(response.context['news_from_category'], ['<News: News title>'])

    def test_multiple_news_from_category(self):
        category = create_category()
        news_1 = create_news(category, 'News title 1')
        news_2 = create_news(category, 'News title 2')
        response = self.client.get(category.get_absolute_url())
        self.assertQuerysetEqual(response.context['news_from_category'], ['<News: News title 2>', '<News: News title 1>'])

为其创建测试的视图

class HomePageView(ListView):
    template_name = 'index.html'
    context_object_name = 'last_20_news'

    def get_queryset(self):
        return News.objects.order_by('-pub_date')[:20].select_related('category')

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super(HomePageView, self).get_context_data()
        context['categories'] = Category.objects.all()
        return context


class NewsFromCategoryView(ListView):
    template_name = 'news/category_page.html'
    slug_url_kwarg = 'category_slug'
    paginate_by = 20
    context_object_name = 'news_from_category'

    def get_queryset(self):
        return News.objects.filter(category__slug=self.kwargs['category_slug']).select_related('category')

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super(NewsFromCategoryView, self).get_context_data()
        context['category'] = Category.objects.get(slug=self.kwargs['category_slug'])
        return context

来自控制台的结果

λ python manage.py test news

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F..F..
======================================================================
FAIL: test_multiple_news_from_category (news.tests.CategoryPageTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Projects\project\news\tests.py", line 59, in test_multiple_news_from_category
    self.assertQuerysetEqual(response.context['news_from_category'], ['<News: News title 2>', '<News: News title 1>'])
  File "C:\Users\zepte\.virtualenvs\project-a8cUl3-w\lib\site-packages\django\test\testcases.py", line 1072, in assertQuerysetEqual
    return self.assertEqual(list(items), values, msg=msg)
AssertionError: Lists differ: ['<News: News title 1>', '<News: News title 2>'] != ['<News: News title 2>', '<News: News title 1>']

First differing element 0:
'<News: News title 1>'
'<News: News title 2>'

- ['<News: News title 1>', '<News: News title 2>']
?                     ^                       ^

+ ['<News: News title 2>', '<News: News title 1>']
?                     ^                       ^


======================================================================
FAIL: test_multiple_news (news.tests.HomePageTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Projects\project\news\tests.py", line 37, in test_multiple_news
    self.assertQuerysetEqual(response.context['last_20_news'], ['<News: News title 2>', '<News: News title 1>'])
  File "C:\Users\zepte\.virtualenvs\project-a8cUl3-w\lib\site-packages\django\test\testcases.py", line 1072, in assertQuerysetEqual
    return self.assertEqual(list(items), values, msg=msg)
AssertionError: Lists differ: ['<News: News title 1>', '<News: News title 2>'] != ['<News: News title 2>', '<News: News title 1>']

First differing element 0:
'<News: News title 1>'
'<News: News title 2>'

- ['<News: News title 1>', '<News: News title 2>']
?                     ^                       ^

+ ['<News: News title 2>', '<News: News title 1>']
?                     ^                       ^


----------------------------------------------------------------------
Ran 6 tests in 0.272s

FAILED (failures=2)
Destroying test database for alias 'default'...

再次运行测试

λ python manage.py test news

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
......
----------------------------------------------------------------------
Ran 6 tests in 0.354s

OK
Destroying test database for alias 'default'...

结果,即每次我运行测试时交换测试( test_multiple_news 和 test_multiple_news_from_category )中的对象( ['', ''] ),我想知道为什么会这样。

【问题讨论】:

    标签: django django-tests


    【解决方案1】:

    通过使用:

    def create_news(category, title, text='news text', pub_date=timezone.now()):
        return News.objects.create(category=category, image=None, title=title, text=text, pub_date=pub_date)
    

    两个项目将具有相同的pub_date。你应该使用:

    def create_news(category, title, text='news text', pub_date=None):
        if pub_date is not None:
            pub_date = timezone.now()
        return News.objects.create(category=category, image=None, title=title, text=text, pub_date=pub_date)

    但仍然有可能这两个项目插入得如此之快以至于它们具有相同的时间戳。因此,最好使用freezegun [GitHub] 之类的工具来确保两者之间的创建时间至少为几毫秒:

    from freezegun import freeze_time
    
    class HomePageTestCase(TestCase):
        # …
    
        @freeze_time('2021-12-26', auto_tick_seconds=15)
        def test_multiple_news(self):
            category = create_category()
            news_1 = create_news(category, 'News title 1')
            news_2 = create_news(category, 'News title 2')
            # …

    您应该将相同的逻辑应用于使 多个 插入彼此靠近的项目。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-10
      • 2013-12-22
      • 2016-06-20
      • 1970-01-01
      • 1970-01-01
      • 2014-11-09
      • 1970-01-01
      相关资源
      最近更新 更多