36


I am new to django unittest and pytest. However, I started to feel that pytest test case is more compact and clearer.

Here is my test cases:

class OrderEndpointTest(TestCase):
    def setUp(self):
        user = User.objects.create_superuser(username='admin', password='password', email='pencil@gmail.com')
        mommy.make(CarData, _quantity=1)
        mommy.make(UserProfile, _quantity=1, user=user)

    def test_get_order(self):
        mommy.make(Shop, _quantity=1)
        mommy.make(Staff, _quantity=1, shop=Shop.objects.first())
        mommy.make(Order, _quantity=1, car_info={"color": "Black"}, customer={"name": "Lord Elcolie"},
                   staff=Staff.objects.first(), shop=Shop.objects.first())

        factory = APIRequestFactory()
        user = User.objects.get(username='admin')
        view = OrderViewSet.as_view({'get': 'list'})

        request = factory.get('/api/orders/')
        force_authenticate(request, user=user)
        response = view(request)
        assert 200 == response.status_code
        assert 1 == len(response.data.get('results'))

And here is the pytest version

def test_get_order(car_data, admin_user, orders):
    factory = APIRequestFactory()
    user = User.objects.get(username='admin')
    view = OrderViewSet.as_view({'get': 'list'})

    request = factory.get('/api/orders/')
    force_authenticate(request, user=user)
    response = view(request)
    assert 200 == response.status_code
    assert 1 == len(response.data.get('results'))

The benefit from pytest is fixture in another file. It makes my test case compact by let them be my input parameters.

Are they any benefit of using Django unittest than pytest?

Update: 1July2017
Update: 5July2017
Update: 1Sep2017
Update: 29Sep2017
Update: 26Dec2017

  1. Pytest reduces your problem when fixtures got mutated over the test. I got testcases that run individually passed, but fail when run thoroughly.
  2. Pytest will show you the assertion output if the error occur. Django unittest does not. I have to put the breakpoint on my own and investigate the error.
  3. Pytest allow you to use real database with simple decorator. Django test does not. You have to create your own customized command for your job
  4. Pytest is generic. Being an generic it means you feel comfortable to work with project outside the Django. For example when you have to build micro-service such as Flask + 3rd parties like APScheduler, PyRad, ... etc. I mention this because my backend life uses Django 50% The rest of the is Python and infra
  5. Pytest is not using multiple inheritance to create my fixtures
  6. Unittest takes advantage on gitlab-ci over Pytest when used with Docker as a runner by smoothly execute without any extra configurations. problem
char
  • 2,063
  • 3
  • 15
  • 26
joe
  • 8,383
  • 13
  • 61
  • 109
  • 7
    Django tests do support fixtures. Just saying... – spectras Jul 05 '17 at 06:54
  • @spectras Hi. please correct if my information is outdated. I really want to know and choose right tools for right situation. Right now I do both of them base on project leader. If I lead I use `pytest`. The others use `Django test` I do follow it. Therefore I am start the question on here and discuss. – joe Jul 05 '17 at 07:28
  • I create fixtures in the method `setUp()` and reuse by inheritance. Are you talking on the same fixtures? – joe Jul 05 '17 at 07:29
  • No, I'm talking about [Django fixtures](https://docs.djangoproject.com/en/1.11/howto/initial-data/) – spectras Jul 05 '17 at 15:45
  • Thank you for your reply. I have not use it because I can not use it with `mommy` – joe Jul 06 '17 at 06:30
  • https://stackoverflow.com/questions/47904245/reset-sequence-in-pytest-django I am unable to find `reset_transaction` in `pytest`. After certain time I will put it here and it might change my mind! – joe Dec 20 '17 at 10:51
  • By the way, `mommy.make` returns created instance. So this code is cleaner `shop = mommy.make(Shop, _quantity=1); mommy.make(Staff, _quantity=1, shop=shop)` – Vladimir Prudnikov Dec 11 '19 at 18:31

1 Answers1

9

i've used Django test for my entire life and now i am using Py.test. I agree that pytest is much cleaner than django itself.

The benefit from pytest is fixture in another file. It makes my test case compact by let them be my input parameters.

In Django unittest you can still use fixtures in other file by using the attribute fixtures = ['appname/fixtures/my_fixture.json']

Pytest will show you the assertion output if the error occur. Django unittest does not. I have to put the breakpoint on my own and investigate the error.

Did you tried to change the --verbose param on python manage.py tests?

A few tips:

  1. There is a package called pytest-django that will help you integrate and using django with pytest.

  2. I think that if you use classes will you not need to use the factory = APIRequestFactory(), the test methods itself they have a parameter called client that is a interface to the python requests module to access your views.

    import pytest
    
    from model_mommy import mommy
    
    @pytest.fixture()
    def user(db):
        return mommy.make(User)
    
    class SiteAPIViewTestSuite:
        def test_create_view(self, client, user):
            assert Site.objects.count() == 0
    
            post_data = {
                'name': 'Stackoverflow'
                'url': 'http://stackoverflow.com',
                'user_id': user.id,
            }
            response = client.post(
                reverse('sites:create'),
                json.dumps(post_data),
                content_type='application/json',
            )
    
            data = response.json()
            assert response.status_code == 201
            assert Site.objects.count() == 1
            assert data == {
                'count': 1,
                'next': None,
                'previous': None
                'results': [{
                    'pk': 1,
                    'name': 'Stackoverflow',
                    'url': 'http://stackoverflow.com',
                    'user_id': user.id
                }]
            }
    
Luan Fonseca
  • 1,467
  • 1
  • 13
  • 22
  • 2
    +1 Thank you for sharing your experience with me. I had tried `fixture.json`. It is not flexible. `model_mommy` is fit for my need. For `--verbose` this is my bad. I did't know about this. Your given example on `client` is clean! Let me try it with incoming project. – joe Apr 20 '18 at 03:08
  • 2
    I also use `model_mommy`, its awesome and work fine. – Luan Fonseca Apr 20 '18 at 14:04
  • 2
    Instead of fixtures I prefer factories with [factory_boy](https://factoryboy.readthedocs.io/en/latest/). I also use those to generate some test data (faker built in) during development. – medihack Jun 26 '20 at 08:17
  • 2
    Model Mommy is no longer maintained and was replaced by [Model Bakery](https://pypi.org/project/model-bakery/). – Oğuzhan Oct 11 '21 at 09:06
  • At first glance pytest is tempting and you write fancy fixtures. At the end those fixtures will haunt you if do not do the teardown properly. You will end up having flaky tests. Your CI/CD pipeline will be stalled and you will spend more time fixing those fixtures and teardown book keeping. And that's a nasty task. – sajid Jan 31 '23 at 12:47
  • My advice after years of experience with pytest and Unittest, I recommend Django unittest with FactoryBoy. At the beginning it looks "awesome" but at the end it's not "aweosme" – sajid Jan 31 '23 at 12:50