5

I'm using mixer to generate my model and running them with pytest. All I wanna do is generate my model only one time and run several tests with the same model I generate.

Here is what I want:

Code

import pytest
from mixer.backend.django import mixer
from weddings.models import Wedding


@pytest.mark.django_db
class TestProductApi(object):

    @pytest.fixture(scope="module")
    def wedding(self):
        wedding = mixer.blend(
            'weddings.Wedding',
        )
        mixer.cycle(12).blend(
            'weddings.Product',
            wedding=wedding,
        )

        mixer.cycle(4).blend(
            'weddings.Product',
            wedding=wedding,
            is_visible=False,
        )

        mixer.blend(
            'weddings.Product',
            wedding=wedding,
            is_active=False,
        )
        return wedding

    def test_number_one(self, wedding):
        print 'running test_number_one'
        print 'wedding.id == {}'.format(wedding.id)
        print 'Wedding.objects.all().count() == {}'.format(Wedding.objects.all().count())
        print 'finished test_number_one'

    def test_number_two(self, wedding):
        print 'running test_number_two'
        print 'wedding.id == {}'.format(wedding.id)
        print 'Wedding.objects.all().count() == {}'.format(Wedding.objects.all().count())
        print 'finished test_number_two'

Output

tests/weddings/api/test_products.pyTestProductApi.test_number_one                                                        0%           running test_number_one
wedding.id == 1
Wedding.objects.all().count() == 1
finished test_number_one
 tests/weddings/api/test_products.pyTestProductApi.test_number_one ✓                                                     50% █████
 tests/weddings/api/test_products.pyTestProductApi.test_number_two                                                       50% █████     running test_number_two
wedding.id == 1
Wedding.objects.all().count() == 0
finished test_number_two

What I'm doing in my tests are not that important, however, I want all of them to run with the same generated wedding object. When I run my tests, a new wedding is created every time I create a test.

Here is the version of what I'm using:
pytest==2.7.1
pytest-django==2.9.1
Django==1.8.8
mixer==5.3.1
python==2.7.6

EDIT 1: I also tried adding a scope to my fixture but that work's only for the first test. If I make a query in the second test, the model doesn't exist, even thou the fixture works just fine.

EDIT 2: Inserting the scope="module" to the fixture and showing the result of the ran tests.

jarussi
  • 1,143
  • 1
  • 9
  • 25
  • Django deliberately runs each test in a transaction so that tests do not affect each other. Why do you need to use the same object for all the tests? – Alasdair Mar 16 '16 at 18:41
  • 1
    I just wanna speed up my test time. I need to generate a lot of models so my test can be effective. And that is taking ~1 seconds for each test. Right now I'm running 12 tests in ~14 seconds :/ – jarussi Mar 16 '16 at 18:44
  • Django's `TestCast` class has a [`SetUpTestData`](https://docs.djangoproject.com/en/1.9/topics/testing/tools/#django.test.TestCase.setUpTestData) method that allows you to create data once for the entire test case. I'm not sure whether `pytest-django` allows something similar. Have you tried using `scope=cls` for your fixture? – Alasdair Mar 16 '16 at 19:01
  • Yes .. I tried with `scope="class"`, `scope="module"` .. They work for the first test .. however the generated model doesn't exist for the next test. It's pretty weird – jarussi Mar 16 '16 at 19:18
  • jarussi: Can you write into you question how do you use scope, because it is a solution for you. Also try to place your fixture `wedding` out of class. And don't forget to remove `self` as parameter. – Sergey Voronezhskiy Mar 18 '16 at 13:22
  • Done Sergey. I also added the results of the tests. – jarussi Mar 22 '16 at 13:44

1 Answers1

1

This worked for me. Give it a try...

import pytest
from mixer.backend.django import mixer
from weddings.models import Wedding

@pytest.fixture(scope="class")
def wedding(self):
    wedding_obj = mixer.blend(
        'weddings.Wedding',
    ) 
    mixer.cycle(12).blend(
        'weddings.Product',
        wedding=wedding_obj,
    ) 

    mixer.cycle(4).blend(
        'weddings.Product',
        wedding=wedding_obj,
        is_visible=False,
    ) 

    mixer.blend(
        'weddings.Product',
        wedding=wedding_obj,
        is_active=False,
    ) 
    return wedding_obj

@pytest.mark.django_db
@pytest.mark.usefixtures("wedding")
class TestProductApi(object):

    def test_number_one(self, wedding):
        print 'running test_number_one'
        print 'wedding.id == {}'.format(wedding.id)
        print 'Wedding.objects.all().count() == {}'.format(Wedding.objects.all().count())
        print 'finished test_number_one'

    def test_number_two(self, wedding):
        print 'running test_number_two'
        print 'wedding.id == {}'.format(wedding.id)
        print 'Wedding.objects.all().count() == {}'.format(Wedding.objects.all().count())
        print 'finished test_number_two'
Brad Larson
  • 168,330
  • 45
  • 388
  • 563