Functional Test Not isolating from database - django

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()
...

Related

Mock an internal object call in a Flask view - with pytest

Based on the following example:
app = Flask(__name__)
#app.route('/users')
def get_users():
return UsersAPI().get_users()
And the following tests (using pytest and pytest-mock):
#pytest.fixture
def users():
return UsersAPI(how_many=1)
def test_simple(users, mocker):
mocker.patch("???", return_value=users)
I simply want to call UsersAPI(how_many=1) instead of UsersAPI(). Is this possible to do?
(if you know how to get done with unittest.mock that is also fine since pytest-mock is simply some pytest wrapper)
Turns out it is as easy as:
#pytest.fixture
def users():
return UsersAPI(how_many=1)
def test_simple(users, mocker):
mocker.patch("path.to.module.UsersAPI", return_value=users)
And this also works:
mocker.patch.object(path.to.module, 'UsersAPI', return_value=users)

How can I pass in a parameter to my TestCase in 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

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

Django unittest with legacy database connection

I have a Django project that pulls data from legacy database (read only connection) into its own database, and when I run integration tests, it tries to read from test_account on legacy connection.
(1049, "Unknown database 'test_account'")
Is there a way to tell Django to leave the legacy connection alone for reading from the test database?
I actually wrote something that lets you create integration test in djenga (available on pypi) if you want to take a look at how to create a separate integration test framework.
Here is the test runner I use when using the django unit test framework:
from django.test.runner import DiscoverRunner
from django.apps import apps
import sys
class UnManagedModelTestRunner(DiscoverRunner):
"""
Test runner that uses a legacy database connection for the duration of the test run.
Many thanks to the Caktus Group: https://www.caktusgroup.com/blog/2013/10/02/skipping-test-db-creation/
"""
def __init__(self, *args, **kwargs):
super(UnManagedModelTestRunner, self).__init__(*args, **kwargs)
self.unmanaged_models = None
self.test_connection = None
self.live_connection = None
self.old_names = None
def setup_databases(self, **kwargs):
# override keepdb so that we don't accidentally overwrite our existing legacy database
self.keepdb = True
# set the Test DB name to the current DB name, which makes this more of an
# integration test, but HEY, at least it's a start
DATABASES['legacy']['TEST'] = { 'NAME': DATABASES['legacy']['NAME'] }
result = super(UnManagedModelTestRunner, self).setup_databases(**kwargs)
return result
# Set Django's test runner to the custom class defined above
TEST_RUNNER = 'config.settings.test_settings.UnManagedModelTestRunner'
TEST_NON_SERIALIZED_APPS = [ 'legacy_app' ]
from django.test import TestCase, override_settings
#override_settings(LOGIN_URL='/other/login/')
class LoginTestCase(TestCase):
def test_login(self):
response = self.client.get('/sekrit/')
self.assertRedirects(response, '/other/login/?next=/sekrit/')
https://docs.djangoproject.com/en/1.10/topics/testing/tools/
You should theoretically be able to use the override settings here and switch to a dif

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.