Testing file upload via a form?

72 views
Skip to first unread message

Derek

unread,
Aug 29, 2017, 2:50:25 PM8/29/17
to django-users
(Python 3.5 and Django 1.10)

I am trying to test a Django form that enables a required file upload.

The form is very simple and includes a field that looks like:

    upload_file = forms.FileField()

The corresponding test to try and check the upload:

def test_form_validation_with_file(self):
    fake_file = ContentFile(b'''Some file content''')
    fake_file.name = 'fake.xls'
    suf_file = SimpleUploadedFile('suf.xls', b'''this is text''')
    data = {
        'upload_file': suf_file,
    }
    form = forms.RequestForm(data=data)
    self.assertTrue(form.is_valid())

The form validation fails i.e. it does not seem to recognise that file data has been suppplied.

I have also tried with the  "fake_file" for the data but without success.

Any help or pointers appreciated.

Thanks
Derek

Melvyn Sopacua

unread,
Aug 31, 2017, 10:48:13 AM8/31/17
to django...@googlegroups.com
​In the documentation of the test client it is all spelled out how to test file uploads.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CAF1Wu3OTCbnw4o749YUz-Pa1-Uo9jkGkd1KybB5rSLnp3eAMDQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.



--
Melvyn Sopacua

Derek

unread,
Sep 1, 2017, 3:08:42 AM9/1/17
to django-users
Thanks Melvyn

I thought my code did follow that approach - but it does not seem to work. So either I have not understood the docs (in which case, a point to the specific item is what I need) or there is some other factor at work.

--
You received this message because you are subscribed to a topic in the Google Groups "Django users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-users/GUStj-3rzD8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-users+unsubscribe@googlegroups.com.

To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

James Schneider

unread,
Sep 1, 2017, 3:28:02 AM9/1/17
to django...@googlegroups.com
It does not appear that you are binding the file to the form correctly. Django forms use a separate argument to the form class for file content. It is not part of the form 'data'.


-James

Derek

unread,
Sep 1, 2017, 4:04:49 AM9/1/17
to django-users
Thanks James, I will try that.

--
You received this message because you are subscribed to a topic in the Google Groups "Django users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-users/GUStj-3rzD8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

Melvyn Sopacua

unread,
Sep 1, 2017, 11:13:37 AM9/1/17
to django...@googlegroups.com
You're not using the test **Client** at all. You're testing the value
of a form.Form instance.

The difference is that the test client constructs an actual request,
using the known URLs. So you'd need a view and url as well.
But these can exist only in the test and to be honest, especially
with uploads, I'm more interested in the upload working when used
in a view, then whether the form works in an environment it's never
going to be used in.

That said, James is right on the money with the payload. It doesn't
however tell you file uploads are going to work, only that a correctly
bound file passes validation.
>>> email to django-users...@googlegroups.com.
>>> To post to this group, send email to django...@googlegroups.com.
>>> Visit this group at https://groups.google.com/group/django-users.
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msgid/django-users/CAF1Wu3OTCbnw4o749YUz-Pa1-Uo9jkGkd1KybB5rSLnp3eAMDQ%40mail.gmail.com.
>>> For more options, visit https://groups.google.com/d/optout.
>>
>>
>>
>>
>> --
>> Melvyn Sopacua
>>
>> --
>> You received this message because you are subscribed to a topic in the
>> Google Groups "Django users" group.
>> To unsubscribe from this topic, visit
>> https://groups.google.com/d/topic/django-users/GUStj-3rzD8/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to
>> django-users...@googlegroups.com.
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users...@googlegroups.com.
> To post to this group, send email to django...@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/CAF1Wu3NR3Wqv56-i3xOo6QGrGU1Et5z3Kg-PM%2BGbBB6j5b2ZGw%40mail.gmail.com.

Derek

unread,
Sep 1, 2017, 3:01:13 PM9/1/17
to django-users
Thanks Melvyn

I already have tests for the processing of data when it has been uploaded - which is actually the critical issue for the application.  The "view" is just really a thin wrapper around the two steps : form display & upload and then the file processing itself : and those are the parts I need tests for.



>>> To post to this group, send email to django...@googlegroups.com.
>>> Visit this group at https://groups.google.com/group/django-users.
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msgid/django-users/CAF1Wu3OTCbnw4o749YUz-Pa1-Uo9jkGkd1KybB5rSLnp3eAMDQ%40mail.gmail.com.
>>> For more options, visit https://groups.google.com/d/optout.
>>
>>
>>
>>
>> --
>> Melvyn Sopacua
>>
>> --
>> You received this message because you are subscribed to a topic in the
>> Google Groups "Django users" group.
>> To unsubscribe from this topic, visit
>> https://groups.google.com/d/topic/django-users/GUStj-3rzD8/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to

>> To post to this group, send email to django...@googlegroups.com.
>> Visit this group at https://groups.google.com/group/django-users.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/django-users/CA%2Bgw1GVt-pwLwdTx_0m2nj-uy0A%3DBQh8L1aeFNnraMCAy%3DP-iw%40mail.gmail.com.
>> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an

> To post to this group, send email to django...@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-users.
> To view this discussion on the web visit
>
> For more options, visit https://groups.google.com/d/optout.



--
Melvyn Sopacua

--
You received this message because you are subscribed to a topic in the Google Groups "Django users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-users/GUStj-3rzD8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-users+unsubscribe@googlegroups.com.

To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

James Schneider

unread,
Sep 3, 2017, 3:07:57 AM9/3/17
to django...@googlegroups.com
On Sep 1, 2017 3:00 PM, "Derek" <game...@gmail.com> wrote:
Thanks Melvyn

I already have tests for the processing of data when it has been uploaded - which is actually the critical issue for the application.  The "view" is just really a thin wrapper around the two steps : form display & upload and then the file processing itself : and those are the parts I need tests for.

I'd have to agree with Melvin. You should be testing your view code as well, which would incorporate the tests for the form class. If the view is broken out interacts badly with the form for whatever reason, the fact that the form works on it's own is irrelevant. Plus it isn't that hard to add in. 

I would test the view even if it is boiler plate code shared by all of your forms, because you need to be certain that the combination of the view and form in question work together.

-James

Derek

unread,
Sep 3, 2017, 4:06:59 AM9/3/17
to django-users
I have been looking for a decent guide that covers testing in a solid, thorough way - there are lots of fragmented pieces that cover bits-and-pieces of what is needed for tests but not all the cases with a start-to-end comprehensive approach for everything ("Obey the Testing Goat" comes closest). I need to cover cases for the admin as well - with actions and intermediate forms, some with file uploads. In those case, I assume (?) that the action logic is equivalent to a view.
 
The Django docs show examples as well but I have not see where they cover everything.

This may all seem like trivial knowledge to people who have already done all this, but I struggle to see the full picture of what a whole test suite should look like, and what the details of all the tests would be.


--
You received this message because you are subscribed to a topic in the Google Groups "Django users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-users/GUStj-3rzD8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

Melvyn Sopacua

unread,
Sep 3, 2017, 10:15:37 AM9/3/17
to django...@googlegroups.com
It certainly isn't trivial.

First and foremost, write fat models and Managers, but lean views.

Rather then putting complex queries in views, I have a strong bias
to writing manager methods (or QuerySet methods, if I feel it's
reusable in more then one Manager - see Manager.from_queryset [1]).

Further more, I tend to use the setup described here [2] also for
projects. But for the `test_settings.py` I use:

from project_app.settings import *

INSTALLED_APPS += ['tests.apps.TestsConfig']

This makes it trivial to test fields on their own, by creating models
that only exist in the test environment.

Normally, you want to test all components on their own, but with
forms being so tightly coupled to and influenced by views and urls,
it is non-trivial to predict what affects your form and thus test for it.
It's easy to get 100% coverage on your form and still know nothing,
because the input variations are important.
Yes, it's possible to do with different initialization, but you're going
to test your views anyway, so why not use the test client, as your
views eventually determine what happens with them and are pretty
much the only way to use them. On top of that, you're testing your
urls for free.

So in general, a Django test suite consists of:
* model tests
* view tests using django.test.Client
* template tests [3]
* command tests [4]
* utility tests

Hope this helps,

[1] https://docs.djangoproject.com/en/1.11/topics/db/managers/#creating-a-manager-with-queryset-methods
[2] https://docs.djangoproject.com/en/1.11/topics/testing/advanced/#testing-reusable-applications
[3] shameless plug warning:
http://django-xtc.readthedocs.io/en/latest/index.html
[4] https://docs.djangoproject.com/en/1.11/ref/django-admin/#django.core.management.call_command
>> django-users...@googlegroups.com.
>> To post to this group, send email to django...@googlegroups.com.
>> Visit this group at https://groups.google.com/group/django-users.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/django-users/CA%2Be%2BciUgbWkGFVrqBWKAYdifP%2BjTchZwHR0-GfPKGcTjP%3DBjfA%40mail.gmail.com.
>>
>> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users...@googlegroups.com.
> To post to this group, send email to django...@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/CAF1Wu3MqT1V85StnBg8D_eqrcjH%2BebjvDW41xg_V1t%3D9%3DeUk-Q%40mail.gmail.com.
>
> For more options, visit https://groups.google.com/d/optout.



--
Melvyn Sopacua

Derek

unread,
Sep 10, 2017, 9:29:07 AM9/10/17
to django-users
Thanks Melvyn

Yes, over time I have come to learn the need for fat models and  Useful Managers, plus having logic not embedded in the views (especially for processing of data arising from a form).  So views are mostly "handlers" to ensure that the forms are presented, the data is retrieved and passed on to a processing method, and then the flow redirected to the right URL.

I have got hung up on the "mechanics" of form testing instead of seeing that they only play a small role in the project.  I will however, persist until I get the grammar correct.

Derek




>> To post to this group, send email to django...@googlegroups.com.
>> Visit this group at https://groups.google.com/group/django-users.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/django-users/CA%2Be%2BciUgbWkGFVrqBWKAYdifP%2BjTchZwHR0-GfPKGcTjP%3DBjfA%40mail.gmail.com.
>>
>> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an

> To post to this group, send email to django...@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-users.
> To view this discussion on the web visit
--
You received this message because you are subscribed to a topic in the Google Groups "Django users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-users/GUStj-3rzD8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-users+unsubscribe@googlegroups.com.

To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
Reply all
Reply to author
Forward
0 new messages