Testing related models without saving

464 views
Skip to first unread message

Roland Swingler

unread,
Jul 16, 2015, 7:21:30 AM7/16/15
to django...@googlegroups.com
Hi all,

I've very recently come to to Django from a rails background, and struggling to do unit testing of Django models without saving to the database as I'm used to in Rails. Lets say you have 2 linked models, for example User and UserProfileDetails, then in my tests I want to set up the structure and not save any of it:

    user = User()
    user.profile_details = UserProfileDetails()
    ...
    # stuff that tests non-persistence related functionality

But I don't seem to be able to do this, because it will raise a RelatedObjectDoesNotExist error, saying UserProfileDetails has no user. Obviously I can get around this by saving the user first, but if I want to not touch the database in tests is there any way I can achieve this?

(also apologies if this has been asked before - I did a quick search of the archives and couldn't find anything).

Thanks in advance,
Roland

Bruno A.

unread,
Jul 16, 2015, 7:32:41 AM7/16/15
to django...@googlegroups.com
You did not quote your models, but I assume your UserProfileDetails has a OneToOne or ForeignKey relationship with User model.

With Django, you generally need to save the related model before adding it to the Foreignkey, as the relationship in UserProfileDetails is using the primary key (called id by default) from User instance, which is populated when the object is saved.

I don't quite understand why you don't want to save the User model first, the unit tests are running on a separate DB schema.

Bruno A.

unread,
Jul 16, 2015, 7:34:35 AM7/16/15
to django...@googlegroups.com


On Thursday, 16 July 2015 12:21:30 UTC+1, Roland Swingler wrote:

Roland Swingler

unread,
Jul 16, 2015, 9:18:20 AM7/16/15
to django...@googlegroups.com
Hi,

Thanks for the link - I'll investigate that further, especially as to whether you can set that dynamically.

I understand that the test db uses a different schema (it's the same in rails), the point is to be able to run tests isolated from having a database at all.

Thanks,
Roland

Javier Guerra Giraldez

unread,
Jul 16, 2015, 9:38:29 AM7/16/15
to django...@googlegroups.com
On Thu, Jul 16, 2015 at 8:18 AM, Roland Swingler
<roland....@gmail.com> wrote:
> I understand that the test db uses a different schema (it's the same in
> rails), the point is to be able to run tests isolated from having a database
> at all.


there are several testing styles, each one with different dogmas.
discussions of the adequacy of them can get very heated and
non-productive.

one of these styles states that each test should be perfectly isolated
from any other conceivable source of errors, including the database,
and in fact stopping short of suspecting the base OS itself (usually).

without trying to get too deep in religious dogma, i'll just say that
Django tests don't favor too much into the "unit" test spectrum;
instead they lean somewhat towards the "integration" camp (although
not totally there, either).

in short, the database is considered a required infrastructure
service, and tests usually assume it works as expected.

--
Javier

Roland Swingler

unread,
Jul 16, 2015, 9:46:20 AM7/16/15
to django...@googlegroups.com
> i'll just say that Django tests don't favor too much into the "unit" test spectrum;

That is what I'm seeing - it is the same with rails out of the box as well. I guess I'm just curious to know whether:

a) the 'unit' test end of the spectrum is feasible if that's what you like
b) what is available in the Django community (if anything, whether libraries, 'ways-of-doing-things' etc.) to support this if it is an approach one wants to take.

Thanks,
Roland

Carl Meyer

unread,
Jul 16, 2015, 12:37:39 PM7/16/15
to django...@googlegroups.com
Hi Roland,
I also write model tests using unsaved models where possible. I don't
think it has significant test isolation benefits (your tests are still
integrating with most of the ORM), but it does have test-suite speed
benefits!

I understand why the change was made in 1.8 to disallow assigning an
unsaved object to a ForeignKey/OneToOneField attribute; in production
code that would almost always be a bug. Personally, though, I've never
been bitten by that bug, I'm confident I could easily find and fix such
a bug if I did write it, and I don't want to give up the ability to use
related unsaved models in tests. So I just use my own subclasses of
ForeignKey and OneToOneField with `allow_unsaved_instance_assignment =
True` set on them (essentially reverting the safety change in 1.8). I
haven't attempted to switch it on dynamically for testing; that should
be possible using a setting and a custom subclass, but I wouldn't choose
to do that; differences between test and production behavior should be
minimized.

Carl

signature.asc

mic...@herrmann.io

unread,
Jul 30, 2015, 7:19:31 AM7/30/15
to Django users, ca...@oddbird.net
Hi all,

I've just been bitten by this new "feature" as well. I completely don't understand this design decision of 1.8. It is very useful to be able to create model classes without having to save them to the database, not just for unit tests but also for experimenting in the shell. The new "feature" breaks this which is a huge PITA, in my opinion.

Could the check for RelatedObjectDoesNotExist not be performed in the save(...) method by Django? Then we would get the best of both worlds: You can create models however you like in unit tests or the shell, and at the same time if you erroneously attempt to save a foreign key which doesn't yet exist you would get the exception.

I feel strongly about this because it is very much against the ease of use which I like so much about Django. Is this the appropriate forum to request this as a feature for 1.9 (or another future Django version)?

Thanks,
Michael

Tim Graham

unread,
Jul 30, 2015, 11:56:33 AM7/30/15
to Django users, mic...@herrmann.io
We are working on that solution: https://github.com/django/django/pull/5060

Michael Herrmann

unread,
Jul 30, 2015, 11:59:57 AM7/30/15
to Tim Graham, Django users
I'm very relieved - thanks Tim! If I can help, please let me know.

Best,
Michael
--
Inline image 1

Michael Herrmann, MSc
Alser Straße 18/26
1090 Wien
Tel.: +43 699 11 65 16 40
Reply all
Reply to author
Forward
0 new messages