Initial data, tests and migrations

26 views
Skip to first unread message

Tom Evans

unread,
Feb 21, 2017, 2:01:30 PM2/21/17
to django...@googlegroups.com
Hi all

I'm having some difficulty working out how I am supposed to provide
initial data for testing purposes, particularly when the initial data
is not immediately pertinent to the test.

For instance, our project uses django_otp, which has some simple
tests. However, these tests create user objects, which then calls in
to other parts of the project code. This code adds users to various
auth.Group, depending upon the user attributes. This code fails after
the first test has been run, because all the auth.Group model
instances are flushed from the database.

Previously, these instances were loaded from a JSON fixtures file,
which used to be the recommended way. For our own tests, we simply
load these fixtures in the setUp portion of the test; obviously we
can't go around modifying tests in third party libraries.
I tried taking them out of the fixtures, and adding them instead in a
data migration, but this also had the same effect - the instances were
there for the first test ran, and then missing for all the subsequent
ones.


What is the "correct" way of ensuring that these instances exist in
the test database before any test is run?

How can I stop them getting wiped out after any test has run?

Cheers

Tom

Melvyn Sopacua

unread,
Feb 21, 2017, 7:48:13 PM2/21/17
to django...@googlegroups.com

On Tuesday 21 February 2017 19:00:42 'Tom Evans' via Django users wrote:

 

> Previously, these instances were loaded from a JSON fixtures file,

 

And you can still do that.

 

> which used to be the recommended way. For our own tests, we simply

> load these fixtures in the setUp portion of the test; obviously we

> can't go around modifying tests in third party libraries.

> I tried taking them out of the fixtures, and adding them instead in a

> data migration, but this also had the same effect - the instances were

> there for the first test ran, and then missing for all the subsequent

> ones.

 

setUp is run between test methods of a test case. setupTestData is a class method on the testcase run once per test case.

>

>

> What is the "correct" way of ensuring that these instances exist in

> the test database before any test is run?

 

All explained in the docs.

Either redeclare the same fixtures for different test cases or reorganize your testcases to share the same fixture(s).

--

Melvyn Sopacua

Tom Evans

unread,
Feb 22, 2017, 9:23:25 AM2/22/17
to django...@googlegroups.com
I think you have misunderstood:

1) The test cases belong to a library and cannot be modified
2) The initial data is populated from a data migration and not from a
fixture, as that is not recommended [1]

Data is placed in to the test database using migrations, but after the
first test has been run the data is flushed out again, causing the
second test to fail.
I would like the all the tests to pass:
* I don't want to put the same data into fixtures as well as migrations (DRY)
* I don't want to modify the 3rd party library.

How?

Cheers

Tom

[1] https://docs.djangoproject.com/en/1.10/howto/initial-data/#providing-initial-data-with-migrations

Tim Graham

unread,
Feb 22, 2017, 9:40:24 AM2/22/17
to Django users
I'm curious if you feel that running django_otp's tests as part of your project's tests is adding value. All third-party apps that I've used (including tests for django.contrib apps*) have moved their tests to a separate directory so that they're not installed along with the application. It's quite difficult for a library to write tests that work with whatever settings a project might provide -- at least that's what we found with tests for contrib apps.

* https://groups.google.com/d/topic/django-developers/nj_Zha341pA/discussion

Adam Stein

unread,
Feb 22, 2017, 9:42:36 AM2/22/17
to django...@googlegroups.com
The URL you refer to mentions about loading data for apps. Doesn't mention anything in regards to tests. Why are fixtures bad for tests? In fact, right above the "Providing initial data with migrations" section is a "See also" box that says "Fixtures are also used by the testing framework to help set up a consistent test environment". It would seem to me that the docs are telling you to use fixtures for tests and use migrations for real data.

Tom Evans

unread,
Feb 22, 2017, 10:07:02 AM2/22/17
to django...@googlegroups.com
OK. How do I load that data from a fixture in a TestCase I cannot modify?

Cheers

Tom

Tom Evans

unread,
Feb 22, 2017, 10:14:26 AM2/22/17
to django...@googlegroups.com
On Wed, Feb 22, 2017 at 2:40 PM, Tim Graham <timog...@gmail.com> wrote:
> I'm curious if you feel that running django_otp's tests as part of your
> project's tests is adding value.

I'm curious whether you think I commonly spend my time doing things
that I don't think add value...

django_otp is simply an example of this issue, but yes, running those
tests would give my project value.

These tests exercise parts of django_otp that interact with parts of
my code. Successful tests indicate that those two parts interoperate
correctly. The tests are successful when run individually, but fail
when run as a suite because data loaded as part of a migration is
flushed away before the second test.

Melvyn Sopacua

unread,
Feb 22, 2017, 10:19:04 AM2/22/17
to django...@googlegroups.com

On Wednesday 22 February 2017 14:22:36 'Tom Evans' via Django users wrote:

> On Wed, Feb 22, 2017 at 12:47 AM, Melvyn Sopacua <m.r.s...@gmail.com> wrote:

> > On Tuesday 21 February 2017 19:00:42 'Tom Evans' via Django users wrote:

 

> >> What is the "correct" way of ensuring that these instances exist in

> >>

> >> the test database before any test is run?

> >

> > All explained in the docs.

> >

> > Either redeclare the same fixtures for different test cases or

> > reorganize your testcases to share the same fixture(s).

>

> I think you have misunderstood:

>

> 1) The test cases belong to a library and cannot be modified

 

So don't use them as is or prompt the authors to update to the new way of things. In transition, you can extend the test cases and simply add a fixture attribute.

 

> 2) The initial data is populated from a data migration and not from a

> fixture, as that is not recommended [1]

 

Data migrations for the project are never relevant for tests, since the test database is empty. You're putting a label on "fixtures" that is only relevant for the provided context. Fixtures are not deprecated, not bad for you and do not mess up your aura.

On one hand It is as Adam says:

" It would seem to me that the docs are telling you to use fixtures for tests and use migrations for real data."

 

Adding to that - fixtures are still a solid way to load application data - only the use of "initial" or "autloaded" data is discouraged.

Fixtures should be used on production databases to selectively provide data, so that the user of the application can load "google_shopping.json" if it wants to publish it's products Google Shopping or not load it, if she doesn't.

 

--

Melvyn Sopacua

Adam Stein

unread,
Feb 22, 2017, 10:23:09 AM2/22/17
to django...@googlegroups.com
Unfortunately, nothing easy comes to mind. My only thought was the possibility of putting your own wrapper around their tests. The idea being is that you call your wrapper which in turns loads the fixtures and calls their tests rather than having Django call their tests directly. This wrapper could be a unit test or be a derivative of the Django test runner. Don't know how feasible either is but I'm guessing neither would be trivial. Maybe I'm wrong, I didn't pursue the thought any more than having a wrapper of some kind.

I was originally just going on your statements that fixtures weren't used in the tests because they weren't recommended (which is not really the case). Hope you figure something out.

Cheers

Tom

Melvyn Sopacua

unread,
Feb 22, 2017, 10:33:43 AM2/22/17
to django...@googlegroups.com

On Wednesday 22 February 2017 15:13:47 'Tom Evans' via Django users wrote:

 

> These tests exercise parts of django_otp that interact with parts of

> my code. Successful tests indicate that those two parts interoperate

> correctly. The tests are successful when run individually, but fail

> when run as a suite because data loaded as part of a migration is

> flushed away before the second test.

 

So they're different tests: they make use of the logic of the library's test suite, but operate on your data. Schoolbook example for inheritance:

 

from django_otp.tests import SuperTest

 

class SuperTestWithMyData(SuperTest):

fixtures = ['my_data']

 

--

Melvyn Sopacua

Tim Graham

unread,
Feb 22, 2017, 10:59:48 AM2/22/17
to Django users
I'm not trying to be antagonistic, sorry if I came off that way. I wanted to point out the difficulties that Django encountered trying to provide "integration" tests like django-otp does. As others suggested, if django-otp provided tools to build your own integration tests, that might be a better way forward.
Reply all
Reply to author
Forward
0 new messages