With py.test, database is not reset after LiveServerTestCase

2024/10/9 10:21:11

I have a number of Django tests and typically run them using py.test. I recently added a new test case in a new file test_selenium.py. This Test Case has uses the LiveServerTestCase and StaticLiveServerTestCase classes (which is a first for me, usually I am using just TestCase).

Adding this new batch of tests in this new file has caused subsequent tests to start failing in py.test (when before they all passed). It appears that the database is not being "reset" after the LiveServerTestCase in py.test. I can tell because of the incrementation of my model's pk values.

When I run these tests using the Django test runner, they all pass and the pk's are reset in subsequent tests; in the py.test test runner the pk's are being incremented in subsequent tests after the LiveServerTestCase is run. So if I have hardcoded in my test to create an object and retrieve it based on the pk I am expecting it fails because the databases are different between Django and py.test.

Any ideas why this might be and how to fix it?

New test test causing the DB behavior:

from django.contrib.staticfiles.testing import StaticLiveServerTestCasefrom selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import Byclass UpdateCountSelenium(StaticLiveServerTestCase):def setUp(self):self.selenium = webdriver.Firefox()self.delay = 3def tearDown(self):self.selenium.quit()def test_ajax_hit(self):self.selenium.get("%s%s" % (self.live_server_url, '/1/'))# waits for javascript to load and tests the ajax viewwait = WebDriverWait(self.selenium, 3)response = wait.until(EC.text_to_be_present_in_element((By.ID, 'counted-value'), 'true'))self.assertTrue(response)
Answer

A LiveServerTestCase and it's subclass StaticLiveServerTestCase both inherit from TransactionTestCase which differs from TestCase in the manner it resets the DB on test case tearDown. Here is the quote from the aforementioned documentation:

Django’s TestCase class (described below) makes use of database transaction facilities to speed up the process of resetting the database to a known state at the beginning of each test. A consequence of this, however, is that some database behaviors cannot be tested within a Django TestCase class. For instance, you cannot test that a block of code is executing within a transaction, as is required when using select_for_update(). In those cases, you should use TransactionTestCase.

TransactionTestCase and TestCase are identical except for the manner in which the database is reset to a known state and the ability for test code to test the effects of commit and rollback:

  • A TransactionTestCase resets the database after the test runs by truncating all tables. A TransactionTestCase may call commit and rollback and observe the effects of these calls on the database.

  • A TestCase, on the other hand, does not truncate tables after a test. Instead, it encloses the test code in a database transaction that is rolled back at the end of the test. This guarantees that the rollback at the end of the test restores the database to its initial state.

As you mentioned, you see the PK counter retained. This is because truncating tables, means dropping all rows, but this generally does not mean the PK counter is reset.

I assume you care about this because you are using asserting objects by specifying a PK (e.g assert YourModel.objects.filter(pk=1).exists().

Instead, I suggest that in your tests, you assert the existence of X objects (e.g assert YourModel.objects.count() == 1, or even assert the specific objects you expect to exist) and then use these objects in your test as you would usually.

https://en.xdnf.cn/q/70031.html

Related Q&A

Using flask wtforms validators without using a form

Im receiving user registration data from an iOS application and Id like to use the validators that come with wtforms to make sure the email and password are acceptable. However, Im not using a flask f…

How to install graph-tool for Anaconda Python 3.5 on linux-64?

Im trying to install graph-tool for Anaconda Python 3.5 on Ubuntu 14.04 (x64), but it turns out thats a real trick.I tried this approach, but run into the problem:The following specifications were foun…

How to quickly encrypt a password string in Django without an User Model?

Based on my current Django app settings, is there a function or a snippet that allows me to view the encrypted password, given a raw string? I am testing some functionality and this would be useful fo…

Embedding multiple gridspec layouts on a single matplotlib figure?

I am using the python graphing library matplotlib to graph several things in a report, and I found myself needing to have several fixed-count graphs above an arbitrary grid of smaller graphs. I search…

Writing integers in binary to file in python

How can I write integers to a file in binary in Python 3?For example, I want to write 6277101735386680763835789423176059013767194773182842284081 to a file in binary in exactly 24 bytes (unsigned, I wi…

Dropping some columns when using to_csv in pandas

I have a data frame which I want to write to tow files, one that contains all of the columns and one that has only a subset of the columns So for this data frame: Out_dataOut[9]: A B …

Setting Max Results in API v4 (python)

In v3 of the API Im seeing that there was a max-results parameter that could be passed to get more than 1000 records. I havent been able to figure out how to pass that parameter in v4 of the API using …

Extract text between two different tags beautiful soup

Im trying to extract the text content of the article from this web page.Im just trying to extract the article content and not the "About the author part".The problem is that all the content a…

Add column to pandas without headers

How does one append a column of constant values to a pandas dataframe without headers? I want to append the column at the end.With headers I can do it this way:df[new] = pd.Series([0 for x in range(le…

Replace NaN values of pandas.DataFrame with values from list

In a python script using the library pandas, I have a dataset of lets say 100 lines with a feature "X", containing 36 NaN values, and a list of size 36.I want to replace all the 36 missing va…