I want to use my test database with data in it which was created when testcase ran, how can i do it?
I tried running normal django test which inherits TestCase and put a break point after test data is been generated. Now if I login to the test_db (which django creates) in different terminal tab through postgres command and query it, no data is shown! can someone explain why this happens?
TestCase wraps tests in an atomic block and rolls back the transaction so that no changes are saved to the database.
If you want changes to be saved, you could use SimpleTestCase, and set databases = __all__ (Django 2.2+), or allow_database_queries = True (earlier versions of Django).
Related
I'm trying to create tests for my Django application but I'm having some trouble creating a test database.
I'd like to keep the existing structure while entering new curated test-information, creating test users, uploading test content, etc. Which I can then populate a test database with so that I have curated data on which I can test edge-cases.
Creating a test database seems simple, just run python manage.py test --keepdb. Getting entries into it seems more difficult.
Is it possible to run Django in "test mode" with the test database being used so that I can use the website UI to enter all the data, or is there some other better way to do it entirely?
I assume you mean testing with unit tests?
Usually you fill the database with fixtures, or some other test data that is populated into the database as a part of the test itself.
Django fixtures: https://code.djangoproject.com/wiki/Fixtures
Fixtureless is a good option, https://pypi.org/project/django-fixtureless/
Factory Boy http://factoryboy.readthedocs.io/en/latest/
These options allow you to fill your database with fake or static data to use in your tests.
I used inspectdb to import the Models schema from MySQL database connected with MySQL Connector/Python.
When I run the tests, the system shows:
django.db.utils.ProgrammingError: Table 'test_mydb.cards' doesn't exist
But the table name is just mydb.cards, not test_mydb.cards
Why is this prefix being added? My app's name is just container.
Django uses unittest module for testing, also it creates a blank database for testing as tests should be run ideally always on same blank database or fixtures filled database.
Tests that require a database (namely, model tests) will not use your
“real” (production) database. Separate, blank databases are created
for the tests.
Regardless of whether the tests pass or fail, the test databases are
destroyed when all the tests have been executed.
Check out if you are having migration sorted for the table test tries to access, as all tables that don't have migrations aren't accessible to test suite without monkeypatching or workarounds
I found the reason: I had managed property to False in models.py Class Meta for each table. I never set it there myself, it is the default after doing inspectdb.
Please read: Django Models Options: Managed
I'm working on a project based on Django REST Framework. So I need to write some test cases for my REST API.
I've written some basic class (let's call it BaseAPITestCase) inherited from standard DRFs APITransactionTestCase.
In this class I've defined setUp method where I'm creating some test user which belongs to some groups (I'm using UserFactory written with FactoryBoy).
When I run my tests, the first one (first test case method from first child class) successfully creates a user with specified groups, but the others don't (other test case methods in the same class).
User groups just don't exist in DB at this time. It seems like existed records are deleted from DB at each new test case run. But how then it works for the first time?
I've read Django test documentation but can't figure out why it happens... Can anyone explain it?
The main question is what I should do to make these tests works?
Should I create user once and store it in object variable?
Should I add some params to preserve user groups data?
Or should I add user groups to fixtures? In that case, how can I create this fixture properly? (All related models, such as permissions and content types)
Simplified source code for illustration:
from rest_framework.test import APITransactionTestCase
class BaseAPITestCase(APITransactionTestCase):
def setUp(self):
self.user = UserFactory(
username='login',
password='pass',
group_names=('admin', )
)
self.client = APIClient()
self.client.force_login(self.user)
def tearDown(self):
self.client.logout()
class CampaignListTest(BaseAPITestCase):
def test_authorized_get(self):
# successfully gets user groups from DB
def test_authorized_post(self):
# couldn't find any groups
TransactionTestCase is a test case to test transactions. As such, it explicitly does not use transactions to isolate tests, as that would interfere with the behaviour of the transactions that are being tested.
To isolate tests, TransactionTestCase rolls back the database by truncating all tables. This is the easiest and fastest solution without using transactions, but as you noticed this will delete all data, including the groups that were generated in a post_migrate signal receiver. You can set serialized_rollback = True on the class, in which case it will serialize all changes to the database, and reverse these changes them after each test. However, this is significantly slower, and often greatly increases the time it takes to run the test suite, so this is not the default.
TestCase does not have this restriction, so it wraps each test case in a transaction, and each individual test in a savepoint. Roll back using transactions and savepoints is fast and allows you to keep the data that was there at the start of the transaction or savepoint. For this reason, it is preferable to use TestCase whenever possible.
This extends to DRF's APITransactionTestCase and APITestCase, which simply inherit from Django's test cases.
In my Django app, I want to add a couple of fields to my existing models and possibly create a new class. I just want to test the new feature and approve if it works.
I can revert the code using git easily. But if I make a makemigrations+migrate then my MySQL database will change and reversing the changes looks like manual deletion of tables and reverting to an old state using a command like django-admin migrate [app_label] [migration_name] (In some cases it looks really cumbersome, example).
I'm wondering if there is any safe practice to try manipulating the database and revert it back to it's initial state safely.
Probable solution #1:
You can utilize the test database that gets created when using django.test.TestCase:
Tests that require a database (namely, model tests) will not use your
“real” (production) database. Separate, blank databases are created
for the tests.
Create some unit tests for your project and make your migrations (without migrating to your production DB, just keep the migrations). Then:
If the database does not exist, it will first be created. Any
migrations will also be applied in order to keep it up to date.
Usually, the database gets destroyed at the end of your tests, but you can keep it between runs:
You can prevent the test databases from being destroyed by using them
test --keepdb option. This will preserve the test database between
runs.
With this trick you can test every migration you make in a fake DB and when you do finalize your model and you have all the migrations history complete, you can migrate on your production DB.
Probable solution #2:
You can make a copy of your database as #albar suggests and have it as a back up while you are working on your new migrations.
Break stuff as much as you want and when you are set and done, replace the "battered" DB with your back up and apply your migration history to it.
I have just moved all of my AJAX validation code over to Django Forms. I need some help updating my tests. I basically have some test data, declared as constants, that are used across all suites. I am then this data repeatedly throughout my tests.
As part of the setup I create some users and login the user that I need:
def setUp(self):
self.client = Client()
create_user(username='staff', email='staff#staff.com',
password='staff', staff=True)
create_user(username='agent', email='agent#agent.com',
password='agent', staff=False)
ShiftType.objects.create(type_id='SI', description='Sales Inbox')
self.client.login(username='staff', password='staff')
The tear down deletes this data (or it used to):
def tearDown(self):
# Clean up the DB
self.client.logout()
ShiftType.objects.all().delete()
User.objects.all().delete()
Event.objects.all().delete()
RecurrentEvent.objects.all().delete()
This was working fine, but now the form does not validate because the form value id given by the users is incremented each time. For example:
ERROR: <ul class="errorlist"><li>employee_id<ul class="errorlist"><li>Select a valid choice. That choice is not one of the available choices.</li></ul></li></ul>
Printing the form allows me to see that the ids are being incremented each time.
Why is this happening even though I am deleting all employees?
I would look into using text fixtures rather than creating and deleting the data every time. This is pretty easy to do in Django. In your tests.py it would look something like this
class BlogTest(TestCase):
fixtures = ['core/fixtures/test.json']
When you do this django will build you a test database, load the fixture into it, run your tests, and then blow away the database after the tests are done. If you want to even use a different database engine (we do this to have our tests use sqlite because it is fast) you can throw something like this into your settings.py
This will make it so the ID's are the same every single time which would fix your problem.