使用pytest-django

时间:2018-09-24 09:50:21

标签: django pytest-django

我试图通过在测试之间缓存对象来加快单元测试的速度。

我知道测试应该相互隔离。但是创建对象的操作很昂贵,因此无需一遍又一遍地创建相同的对象。

最初,我以为我可以从setup_class调用固定装置,但是显然这是行不通的。因此,我刚刚编写了一个简单的函数,可以在每次测试开始时进行调用。这几乎有效。但是,相关对象为空。

以下是一些代码:

models.py:

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, related_name="books")

tests.py:

import factory
import pytest
from faker import Faker
from django.db import models

from models import Book, Author

fake = Faker()

class AuthorFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Author
    name = factory.Faker('name')

class BookFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Book
    title = factory.Faker('sentence')
    author = factory.SubFactory(AuthorFactory)

def make_an_author(**kwargs):

    n_books = kwargs.pop("n_books", 10)

    author = AuthorFactory.create(**kwargs)
    for i in range(n_books):
        BookFactory.create(author=author)

    return author

@pytest.mark.django_db
class TestAuthor:

    N_AUTHORS = 10
    cached_authors = []

    def cache_authors(self, n_authors):
        current_n_authors = len(self.cached_authors)
        if current_n_authors < n_authors:
            self.cached_authors.extend(
                [
                    make_an_author(n_books=2)
                    for i in range(current_n_authors, n_authors)
                ]
            )

    def test_one(self, cache_authors):
        self.cache_authors(10)
        author = fake.choice(self.cached_authors)
        # THIS WORKS!
        assert author.books.count() != 0

    def test_two(self, cache_authors):
        self.cache_authors(10)
        author = fake.choice(self.cached_authors)
        # THIS FAILS!
        assert author.books.count() != 0

每次第一次测试后,作者与书籍之间的反向关系都是空的。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

这里最好的选择也许是在缓存Book时预取Author对象。当前,Book是通过RelatedManager上的Author按需查找的。该查找不适用于第二个测试,因为在最初缓存对象的第一个测试之后,事务被拆除。

您可以尝试:

def make_an_author(**kwargs):

    n_books = kwargs.pop("n_books", 10)

    author = AuthorFactory.create(**kwargs)
    for i in range(n_books):
        BookFactory.create(author=author)

    # Prefetch the books before caching the author
    author = Author.objects.prefetch_related('books').get(pk=author.pk)

    return author