Using django-discover-runner without database - django

I'm trying to use django-discover-runner to test my app. It's basically a WebService frontend, so it doesn't include a database, and, apparently, django-discover-runner doesn't like that.
Looking in other questions, I've seen that with plain Django, I should inherit from DjangoTestSuiteRunner and set settings.TEST_RUNNER. It works fine. But django-discover-runner uses its own discover_runner.DiscoverRunner class, so I tried this:
from discover_runner import DiscoverRunner
class DBLessTestRunner(DiscoverRunner):
def setup_databases(self):
pass
def teardown_databases(self, *args):
pass
But it doesn't work. I get this error message:
ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.
Any idea how to get django-discover-runner working without a DataBase?

In Django 1.6 the standard Django TestCase inherits from TransactionTestCase which attempts to access the database.
To fix the problem in your test class inherit from SimpleTestCase rather then TestCase:
from django.test import SimpleTestCase
class TestViews(SimpleTestCase):
...
You should now be able to run your tests with out setting up the database.

Related

Could not import 'cookbook.schema.schema'

I am going through the official tutorial provided by graphene-python for their library.
I, like a few others I have seen online, am having some serious issues trying to simply import the schema file within the project folder (project_name/schema.py). For reference, the project_name is cookbook as it is denoted within the tutorial.
This is within my settings.py:
GRAPHENE = {
'SCHEMA': 'cookbook.schema.schema'
}
and this is in the schema file tiself (project_name/schema.py):
import graphene
import cookbook.schema
class Query(cookbook.schema.Query, graphene.ObjectType):
# This class will inherit from multiple Queries
# as we begin to add more apps to our project
pass
schema = graphene.Schema(query=Query)
The error that I am getting is:
Could not import 'cookbook.schema.schema' for Graphene setting 'SCHEMA'. AttributeError: module 'cookbook' has no attribute 'schema'.
I have also tried a few other tutorials as well, but haven't had any luck. My project is on django 2.0.2 and graphene 2.0.1. Any help would be much appreciated.
Did you add this to your installed apps?
INSTALLED_APPS = [
'graphene_django',
]
the error says that cookbook has no attribute schema.
Therefore the import cookbook.schema is not working in your schema.py
the example says
import cookbook.ingredients.schema
I actually had incompatible versions of Django, Graphene and Django-environ.
To solve, I made a virtualenv using mkvirtualenv. After that, I was able to follow this tutorial without any issues. It is capable of being stood up without a virtual environment, but it was far easier to just define one and get moving with a clean slate.

what is the best way to test modules in views?

I have gone through this post, but it didn't contain any relevant answer.
I am using Django 1.11 , and my views.py is modular (not class based).
I want to test views modules (functions) in the shell, in django's python shell.
>>> python manage.py shell
By directly importing views like:
>>> from my_app import views
It works, but this doesn't seem to be preferred way to me.
Is there any preferred way or shall I import views from django in shell or copy the function directly ? What is the best practice for this?
So your going to be much better off just writing Django tests for your views instead of trying to run them from the shell since it will be the same code, but you will be able to easily run the test multiple times.
So to create a test for a single view you would create a tests.py in your django app and write test for the view using django's test client. This test client is a dummy web browser that can be used to make http requests. A simple tests.py would look like this:
from django.tests import TestCase, Client
class MyViewsTestCase(TestCase):
def setUp(self):
self.client = Client() #This sets up the test client
def test_my_view(self):
# A simple test that the view returns a 200 status code
# In reality your test needs to check more than this depending on what your view is doing
response = self.client.get('the/view/url')
self.assertEqual(response.status_code, 200)
you would then run this with the commands python manage.py test or django-admin test from your terminal
Again you could do this from the shell, but it's going to be better in the long run to use the test framework
Django has some good docs on writing and running tests here: https://docs.djangoproject.com/en/2.0/topics/testing/overview/
and info on the test client along with some other testing tools here: https://docs.djangoproject.com/en/2.0/topics/testing/tools/

Django built-in User Model implementation

I'm trying to use the built in User model provided by Django in my app, but I'm not sure how to implement it (i.e., what does my models.py file actually look like?) I'm starting off by building a simple login form with the Django auth system.
I'm seeing multiple examples on the web where they import User but never define anything. Like so
from django.db import models
from django.contrib.auth.models import User
#nothing similar to defining User (i.e. 'class User: #fields')
What I'm assuming is by importing User, you don't have to define anything, since it's already been defined, but when I go to run "python manage.py sql 'name'" nothing is executed.
You don't need a models file for the user, because Django already supplies one. You just need to ensure that django.contrib.user is in INSTALLED_APPS.
The only reason you would need to import User into another models file is if you wanted to add a ForeignKey from one of your own models to the User model. In all likelihood, you do want to do that eventually; but you don't need to just in order to get the user models created.

Django testing: TemplateDoesNotExist when loading fixtures. Why?

I have an automatic welcome message generated from template, which is sent whenever a new user is created (through a post_save signal for the User model). Everything works as it should, except when I run manage.py test.
Django keeps complaining:
Problem installing fixture '.../lib/python2.7/site-packages/django/contrib/auth/fixtures/context-processors-users.xml
...
TemplateDoesNotExist users/email_welcome.html
when trying to load the django.contrib.auth fixtures for testing.
Why is it so? Are the template loaders not present when loading fixtures? What could be a solution to this?
I don't know why there is a problem with this template (it works for me), but probably during fixtures loading you don't want to generate this email. In this situation you can use raw argument wich is sent with signal. From Django docs about raw:
A boolean; True if the model is saved exactly as presented (i.e. when
loading a fixture). One should not query/modify other records in the
database as the database might not be in a consistent state yet.
So your code should look like this:
#receiver(post_save, sender=User)
def generate_email(sender, instance, created, raw, **kwargs):
if not raw:
# generate email from template

Mocking Django Storages Model ImageField backend S3

I have a model with an ImageField that is backed by django-storages' S3Boto. I have a test the exercises the "upload image" view, but the fact that it is uploading the image to S3 is slowing down my test suite.
In the interest of speeding up my tests, what is the best practice for dealing with this issue? Should I mock out S3Boto? Perhaps there is a memory backed storage backend that works well for testing (automatic cleanup would be nice!)?
I just had this problem too. I got much faster tests by using dj-inmemorystorage.
The quick way of setting this up is by creating a test_settings.py in the same folder as your settings:
from settings import *
DEFAULT_FILE_STORAGE = 'inmemorystorage.InMemoryStorage'
...and calling ./manage.py test --settings=project.test_settings to run the tests.
My preferred way is to set up a custom test runner:
In project/test_runner.py:
from django.conf import settings
from django.test.runner import DiscoverRunner
class FastTestRunner(DiscoverRunner):
def setup_test_environment(self):
super(FastTestRunner, self).setup_test_environment()
# Don't write files
settings.DEFAULT_FILE_STORAGE = 'inmemorystorage.InMemoryStorage'
# Bonus: Use a faster password hasher. This REALLY helps.
settings.PASSWORD_HASHERS = (
'django.contrib.auth.hashers.MD5PasswordHasher',
)
Note: This also sets the PASSWORD_HASHER, because it significantly improves User creation time. This should NOT be set in production.
In project/settings.py:
TEST_RUNNER = 'project.test_runner.FastTestRunner'
The requirements:
pip install dj-inmemorystorage
UPDATE: changed from django-inmemorystorage to dj-inmemorystorage.
UPDATE 2: Removed django-discover-runner, as it's now the default test runner in django, and fixed the link to the PASSWORD_HASHER related blog post.
I also use S3Boto but for testing, I prefer having custom settings which include using the file system storage. You can have your custom settings declared in a file which you can then import and use in your test cases. Even so, you can mock the file storage so that the files are not actually written to disk.
Here's a sample test_settings.py
# myproject/myproject/test_settings.py
from django.test import override_settings
common_settings = override_settings(
DEFAULT_FILE_STORAGE='django.core.files.storage.FileSystemStorage',
PASSWORD_HASHERS=(
'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',
),
)
Usage:
from django.test import TestCase
from myproject.test_settings import common_settings
#common_settings
class MyTestCase(TestCase):
"""Tests go here"""
On mocking the file system storage you can check out my answer here on SO.
Just ran into this as well so I thought I'd put my solution up. My solution uses Mock
import mock
from django.core.files.storage import FileSystemStorage
from django.test import TestCase
class ATestCase(TestCase):
def setUp(self):
# Stuff Happens
def tearDown(self):
# more Stuff
#mock.patch('storages.backends.s3boto.S3BotoStorage', FileSystemStorage)
def test_file_stuff(self):
self.assertMagicPonies(True)
Some gotchas - make sure you have a sane MEDIA_ROOT setup in the settings. as of django 1.4, you can't use the testing context manager to override MEDIA_ROOT, so you need a separate settings config for it (https://code.djangoproject.com/ticket/17787) This was fixed in 1.6. Also, make sure your upload_to works in normal filesystem, or you will get permission errors.
I would propose to use the standard Django Storage for testing, where you can a define custom path for storage and cleanup that path in your test suite once your done. Both the storage and the path can be set in the settings and overwritten for testing.