How can I pass in a parameter to my TestCase in Django? - django

Using an edited version of the example from Django's own doc, lets say my code looks like this:
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def __init__(self, animal_family):
self.animal_family = animal_family
def setUp(self):
Animal.objects.create(name="lion", sound="roar", family=self.animal_family)
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
self.assertEqual(lion.speak(), 'The mammal lion says "roar"')
Basically, I want to pass in the animal_family parameter into my test, or something similar at least from my terminal. Something like this
python manage.py test myapp.tests.AnimalTestCase 'mammal'
Obviously, the above command does not work. I want to send the 'mammal' as the animal_family to the __init__ method in my test class.
Help would be greatly appreciated.

Whilst self-contained tests should be the best practice, if you really wanted to do this you could set an environment variable when you execute the test command.
For example:
import os
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def setUp(self):
# Retrieve the animal family from the environment variable
animal_family = os.environ['animal_family']
Animal.objects.create(name="lion", sound="roar", family=animal_family)
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
self.assertEqual(lion.speak(), 'The mammal lion says "roar"')
And then call the test command such as:
export animal_family=mammal;python manage.py test myapp.tests.AnimalTestCase

Related

pytest django TestCase give strange failures with `--pdb`

I have a very simple class which fails on any version of pytest>3.0.0. When I invoke the tests with --pdb.
from django.test import TestCase
class TestTestCase(TestCase):
"""Tests for the TestCase class."""
def test_that_client_exists(self):
"""Assert that the class has a client."""
assert self.client
I am using the following version:
platform Linux
Python 2.7.11
pytest-3.3.1
py-1.5.2
pluggy-0.6.0
django-2.9.2
And I get the following error:
self = <myproject.tests.test_test_case.TestTestCase testMethod=test_that_client_exists>
def test_that_client_exists(self):
"""Assert that the class has a client."""
> assert self.client
E AttributeError: 'TestTestCase' object has no attribute 'client'
However, if I downgrade to pytest==3.0.0 and pluggy-0.3.1, the code executes without any issues. My question is this, what is going on? What could be causing this?
It is as if pytest is calling the test_that_client_exists but is not calling __call__ which calls _pre_setup.
Has anyone seen anything like this?
If I remember correctly, pytest doesn't setup the class the way a standard django test is expected to be called.
I would remove the TestCase inheritance and manually add in the client.
from django.test import Client
class TestTestCase():
"""Tests for the TestCase class."""
client = Client()
def test_that_client_exists(self):
"""Assert that the class has a client."""
assert self.client

Functional Test Not isolating from database

I am having a problem where my functional test is not isolating from the main database, there is data left over from the test. I ran python manage.py flush and the test works, but when I run the test again the data created by the test that should have been deleted is still there making my test fail. I am currently only using SQLite.
functional_test.py
from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class NewUserTest(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(15)
def tearDown(self):
self.browser.quit()
def test_user(self):
#Some test
You forgot to indent your method definitions (the statements that begin with "def"). As a result, the Python interpreter thinks that you've defined a new class, called NewUserTest, that contains no attributes, and three top-level functions.
To solve the problem, simply indent the "def" statements by an appropriate amount (4 spaces is the standard convention amongst the Python community). It should look like this:
class NewUserTest(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(15)
def tearDown(self):
self.browser.quit()
...

Nose #with_test not working

I have a situation where for some of the tests, I require to use different setup method than I have defined for all, And for this I though to use #with_setup decorator of nose.
However this doesn't seem to be working.
code:
import unittest
from nose.tools.nontrivial import with_setup
__author__ = 'gaurang_shah1'
class Demo(unittest.TestCase):
def setup_func(self):
print "setup_func"
def teardown_func(self):
print "teardown function"
def setUp(self):
print "setup"
#with_setup(setup_func, teardown_func)
def test_setup(self):
print "test setup"
I am expecting following output,
setup_func
test setup
teardown_func
However I am getting following output, is there anything wrong I am doing here.
setup
test setup
You are constructing a unittest subclass, and as such it will always use unittest.setUp and tearDown methods for the test. As described in the documentation:
Note that with_setup is useful only for test functions, not for test
methods or inside of TestCase subclasses.
If you want to use #with_setup, drop the class all together:
from nose.tools.nontrivial import with_setup
def setup_func():
print "setup_func"
def teardown_func():
print "teardown function"
#with_setup(setup_func, teardown_func)
def test_something():
print "test"
Or better yet, create another unittest class that does your custom setUp function.

autodoc a class that extends a mocked class

I'm trying to run autodoc over a class that extends an external class.
I've used mock so that the import is accepted.
For that I used what was described in this blog http://blog.rtwilson.com/how-to-make-your-sphinx-documentation-compile-with-readthedocs-when-youre-using-numpy-and-scipy/
import mock
MOCK_MODULES = ['de', 'de.xyz', 'de.xyz.class_that_is_extended']
for mod_name in MOCK_MODULES:
sys.modules[mod_name] = mock.Mock()
The python file I try to document looks like this:
from de.xyz import class_that_is_extended
class extending_class (class_that_is_extended):
'''
docstring
'''
After running sphinx the result is, that just the class name plus the link to the source is shown.
When I change the line "class extending_class (class_that_is_extended):"
to "class extending_class (object):" sphinx/autodoc generates the documentation with docstring.
How can I leave the class as is and still get the docstring in the documentation?
Using the apporach posted here:
Sphinx-doc :automodule: with Mock imports
I just changed this line:
sys.modules[mod_name] = mock.Mock()
to:
sys.modules[mod_name] = mock.Mock(class_that_is_extended=object)
and removed 'de.xyz.class_that_is_extended' from MOCK_MODULES
I met the same problem, and my solution was to return object directly from Mock on attribute access.
from unittest.mock import MagicMock
MOCK_MODULES = [
# modules to mock
'kivy.uix.floatlayout',
]
MOCK_CLASSES = [
# classes you are inheriting from
"FloatLayout",
]
class Mock(MagicMock):
#classmethod
def __getattr__(cls, name):
if name in MOCK_CLASSES:
return object
return MagicMock()
sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)

Django test script to pre-populate DB

I'm trying to pre-populate the database with some test data for my Django project. Is there some easy way to do this with a script that's "outside" of Django?
Let's say I want to do this very simple task, creating 5 test users using the following code,
N = 10
i = 0
while i < N:
c = 'user' + str(i) + '#gmail.com'
u = lancer.models.CustomUser.objects.create_user(email=c, password="12345")
i = i + 1
The questions are,
WHERE do I put this test script file?
WHAT IMPORTS / COMMANDS do I need to put at the beginning of the file so it has access to all the Django environment & resources as if I were writing this inside the app?
I'm thinking you'd have to import and set up the settings file, and import the app's models, etc... but all my attempts have failed one way or another, so would appreciate some help =)
Thanks!
Providing another answer
The respondes below are excellent answers. I fiddled around and found an alternative way. I added the following to the top of the test data script,
from django.core.management import setup_environ
from project_lancer import settings
setup_environ(settings)
import lancer.models
Now my code above works.
I recommend you to use fixtures for these purposes:
https://docs.djangoproject.com/en/dev/howto/initial-data/
If you still want to use this initial code then read:
If you use south you can create migration and put this code there:
python manage.py schemamigration --empty my_data_migration
class Migration(SchemaMigration):
no_dry_run = False
def forwards(self, orm):
# more pythonic, you can also use bulk_insert here
for i in xrange(10):
email = "user{}#gmail.com".format(i)
u = orm.CustomUser.objects.create_user(email=email, password='12345)
You can put it to setUp method of your TestCase:
class MyTestCase(TestCase):
def setUp(self):
# more pythonic, you can also use bulk_insert here
for i in xrange(10):
email = "user{}#gmail.com".format(i)
u = lancer.models.CustomUser.objects.create_user(email=email,
password='12345')
def test_foo(self):
pass
Also you can define your BaseTestCase in which you override setUp method then you create your TestCase classes that inherit from BaseTestCase:
class BaseTestCase(TestCase):
def setUp(self):
'your initial logic here'
class MyFirstTestCase(BaseTestCase):
pase
class MySecondTestCase(BaseTestCase):
pase
But I think that fixtures is the best way:
class BaseTestCase(TestCase):
fixtures = ['users_for_test.json']
class MyFirstTestCase(BaseTestCase):
pase
class MySecondTestCase(BaseTestCase):
fixtures = ['special_users_for_only_this_test_case.json']
Updated:
python manage.py shell
from django.contrib.auth.hashers import make_password
make_password('12312312')
'pbkdf2_sha256$10000$9KQ15rVsxZ0t$xMEKUicxtRjfxHobZ7I9Lh56B6Pkw7K8cO0ow2qCKdc='
You can also use something like this or this to auto-populate your models for testing purposes.