Using Selenium within Django I'm trying to run 2 acceptance tests on my django app. The first test registers a new user of my app, the second one logs that user in to the system and tries to perform an action. However, when running the tests, between the first and second tests, the user is erased from the database. It seems the database is wiped between each test. All the documentation I have seen indicates this isn't supposed to be happening.
How can I prevent this from occurring?
Note: Both the setUpClass and tearDownClass methods of my Test Class have #classmethod decorators. Also, the browser doesn't close between the two tests running.
Related
I am currently writing test cases for views, Which eventually uses database also.
By default a test database is being created and removed after test are run.
As the database itself is development database, I don't want my test to create a separate db but use exciting only.
Also I will like to bring to your notice, that in my environment, database are created and provided and django can't run migration or create database.
How can I create unittest which uses real database ?
I think the primary reason for this question is because your django database user is not provided with the create/drop database permission.
Django needs to create and drop a test database for the purpose of unit testing. It cannot use an existing database for this purpose. Why we are not allowed to use an existing database in the unit test is because, the data can be modified by anyone who has the same database permission and django may not have control over the updates they make, This might end up in an unsuccessful unit test.
This is clearly explained in another question's answer
If your DB Admin can provide your Django user the required access for the Test module to work as expected, You can make use of the Fixtures. Fixtures are like data files, can be created from your development environment and then can be used in the Unit test Setup to import the data from Fixtures to the test database created by Django.
The ultimate purpose of any Unit test framework will be to test the functionality of the Back end code logic with a data which is not likely to change. As mentioned in the above links, The Functional testing and Regression Testing is there to cover the real database.
For more details on Fixtures visit Using Fixtures with Django Test Cases
I'm using Django(1.8) + DRF + uwsgi + nginx and trying to unit-test API that I've made. To run tests I need to populate db (create users, for example) and use this data in all tests. So I've tried two ways:
Create directly in TestCase.setUp:
class ApiTests(TestCase):
def setUp(self):
Account.objects.create_user(username='username', password='password')
Or use fixtures:
class ApiTests(TestCase):
fixtures = ['dump.json']
Next I run my project through supervisor:
system("service supervisord startall")
After everything is ready I try to access my API in test to login, using:
login_data = {"username": "username", "password": "password"}
rslt = client.post(HOST_NAME + '/login/', data=login_data)
... but I can't authorize, because users somehow don't exist in the db!
As I've found in the docs to Django tests, TestCase doesn't write data into db, but store it in a transaction, that is rolled back after testing. And as I can see I can get this data only on test-side (using User.objects.all() that is showing that users are created), but not on my nginx-server-side (User.objects.all() on this side shows 0 items).
ATM I can see few options:
Somehow force TestCase to commit data into db.
Populate data in other methods (but which?).
Use different testing libs.
Could you please help?
You shouldn't use web server to test django views even though in reality views do need to be driven by web servers. In order to test request/response behavior, you should use django test client. Django doc has excellent example about that, quoting:
>>> from django.test import Client
>>> c = Client()
>>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
>>> response.status_code
200
>>> response = c.get('/customer/details/')
>>> response.content
b'<!DOCTYPE html...'
On top of that, the doc explains in details how to do GET, POST request and how to test view's response, etc. Hope that makes sense.
Yes! You've already identified the problem. Django TestCase executes in its own little insulated environment. It will create test database prefixed with test_ at the beginning of each suite run, and will execute each test in a transaction, so even if you start the the test suite, pause it after initialization, set the django config that supervisord points to to the test database, continue test execution you will still not see any data.
The reason you will not see any data in the example above is because the test has its own transaction, then when you make a request to your webserver, the webserver will open up a different transaction and will not be able to see the uncommitted data from your test.
To test your views (in my experiences) django TestCases and test clients, usually get you 95% there. They are very fast because each test is executed in a transaction, they expose a test client, that mimics a request (url routing, middleware, view loading, template processing, etc).
Using TestCase should faithfully test all your logic and database interactions, but it still leaves a gap of if supervisor, nginx, uwsgi, django app are functioning correctly. When you have extensive coverage using TestCase simple integration/smoke tests should suffice to verify the services above can communicate correctly. Ie bring up the stack, hit a status page that will test -> Supervisor -> Nginx -> uwsgi -> django -> DB -> back out.
There are def a lot of options for purely functional tests, but why test at a flaky , timely to maintain level when django provides you the tools to verify your application in a reliable, quick, easy to use manner?
If you need a server to be available to a browser for a browser based test, django provides LiveServerTestCase
If you need to write extensive functional tests I have found great success in exposing fixutre creation methods as API methods. This way your tests would be executed AGAINST a stack, an arbitrary stack, in this case it will be against a test stack you bring up locally, but since the tests are separate they could be executed against a QA or staging or even prod stack.
All my QUnit tests run okay with ReSharper, but QUnit's generated page will be shown only once. The session will be gone at page reload or even after trying to filter the tests in the filter options (Chrome gives me ERR_CONNECTION_REFUSED). "Save and restore Unit Test Sessions" is marked.
Does this have something to do with the tests always running in a different port? I wanted the page to stay where it is for later use, but I can't figure out how to do it. How do I make the session last without the connection being refused after a page reload?
as explained in this question and in django docs, when using SimpleTestCase in unit testing, django should not create test database (which takes too long).
Inside one of my applications which is called "search, I have some unit test inherited from SimpleTestCase. this is tests.py inside search application:
class TokenizerTestCase(SimpleTestCase):
def test_one(self):
self.assertItemsEqual(1, 1)
When I call python manage.py test search.tests.TokenizerTestCase it takes too long to build default database. does anybody know why it is creating database for test?
By default SimpleTestCase creates a test database. You can extend the class for your own functionality. If you do not want to create a database of your own in each and every setup setup your own test environment extending the classes.
Override the _pre_setup and _post_teardown methods. For more information read the source code for TransactionTestCase to see how it creates the test database structure.
Read the source code here
I'm developing sites on django I'm think what most problems may be found by using smoke coverage tests method. But (in most cases) write the tests to check response code is 200 for every app, every view, and every url is so bored (e.g. when you are develop few sites parallel). I have a question: How can I automate this process, may be exist some complete solutions to generate some common tests for django.
Thanks!
Best practices:
If it can break, it should be tested. This includes models, views,
forms, templates, validators, and so forth.
Each test should generally only test one function.
Keep it simple. You do not want to have to write tests on top of
other tests. Run tests whenever code is PULLed or PUSHed from the
repo and in the staging environment before PUSHing to production.
When upgrading to a newer version of Django:
-upgrade locally,
-run your test suite,
-fix bugs,
-PUSH to the repo and staging, and then
-test again in staging before shipping the code.
https://realpython.com/blog/python/testing-in-django-part-1-best-practices-and-examples/
Django provides a small set of tools that come in handy when writing tests.
The test client
The test client is a Python class that acts as a dummy Web browser, allowing you to test your views and interact with your Django-powered application programmatically.
Some of the things you can do with the test client are:
Simulate GET and POST requests on a URL and observe the response –
everything from low-level HTTP (result headers and status codes) to
page content.
See the chain of redirects (if any) and check the URL and status code
at each step.
Test that a given request is rendered by a given Django template,
with a template context that contains certain values.
Overview and a quick example
To use the test client, instantiate django.test.Client and retrieve Web pages:
from django.test import Client
c = Client()
response = c.post('/login/', {'username': 'john', 'password': 'smith'})
response.status_code
200
response = c.get('/customer/details/')
response.content
'<!DOCTYPE html...'
As this example suggests, you can instantiate Client from within a session of the Python interactive interpreter.
Testing responses
The get() and post() methods both return a Response object. This Response object is not the same as the HttpResponse object returned by Django views; the test response object has some additional data useful for test code to verify.
Making requests
Use the django.test.Client class to make requests.
class Client(enforce_csrf_checks=False, **defaults)
Exceptions
If you point the test client at a view that raises an exception, that exception will be visible in the test case. You can then use a standard try ... except block or assertRaises() to test for exceptions.
Provided test case classes
Normal Python unit test classes extend a base class of unittest.TestCase. Django provides a few extensions of this base class:
Hierarchy of Django unit testing classes (TestCase subclasses)
Hierarchy of Django unit testing classes
For detailed information and more examples visit https://docs.djangoproject.com/en/1.7/topics/testing/tools/