Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between TestCase and TransactionTestCase classes in django test

Please explain the difference between the TestCase class and TransactionTestCase class. I have read the documentation but it's only saying that TestCase runs tests in a database transaction and uses rollback to "undo" the test in the database, and if you need to manually manage transactions within your test, you would need to use django.test.TransactionTestCase.

Please help me understand the actual difference with an example. In what condition will TestCase fail? Do rollbacks happen automatically or do we have to write code to do the rollback?

like image 822
vishnu m c Avatar asked Jun 09 '17 06:06

vishnu m c


People also ask

What is TestCase in Django?

The best base class for most tests is django. test. TestCase. This test class creates a clean database before its tests are run, and runs every test function in its own transaction. The class also owns a test Client that you can use to simulate a user interacting with the code at the view level.

What is SimpleTestCase?

SimpleTestCase is the simplest one. It provides the basic features of unittest. TestCase plus some Django extras. It blocks database access by default, because it doesn't do anything to isolate changes you would make there. You should use it for testing components that don't need the database.

How do you write test cases in Django?

Writing tests TestCase ) in any file whose name begins with test , automatically build a test suite out of those test cases, and run that suite. For more details about unittest , see the Python documentation. Where should the tests live? The default startapp template creates a tests.py file in the new application.

What is client in Django test?

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.


1 Answers

The main difference between TestCase and TransactionTestCase is that TestCase wraps the tests with atomic() blocks ALL THE TIME. From the documentation:

Wraps the tests within two nested atomic() blocks: one for the whole class and one for each test

Now imagine that you have a method that should raise an error if it is not wrapped inside atomic() block. You are trying to write a test for that:

def test_your_method_raises_error_without_atomic_block(self):
    with self.assertRaises(SomeError):
        your_method()

This test will unexpectedly fail! The reason is, you guessed it, TestCase wraps the tests with atomic() blocks ALL THE TIME. Thus, your_method() will not raise an error, which is why this test will fail. In this case, you should use TransactionTestCase to make your test pass.

select_for_update() is a clear case in point:

Evaluating a queryset with select_for_update() in autocommit mode on backends which support SELECT ... FOR UPDATE is a TransactionManagementError error

From the TransactionTestCase documentation:

with TestCase class, you cannot test that a block of code is executing within a transaction, as is required when using select_for_update()

And if we take a look at the documentation of select_for_update(), we see a warning:

Although select_for_update() normally fails in autocommit mode, since TestCase automatically wraps each test in a transaction, calling select_for_update() in a TestCase even outside an atomic() block will (perhaps unexpectedly) pass without raising a TransactionManagementError. To properly test select_for_update() you should use TransactionTestCase.

Hope it helps!

like image 71
Jahongir Rahmonov Avatar answered Oct 22 '22 21:10

Jahongir Rahmonov