2.9 KiB
2.9 KiB
Chapter 6. Improving Functional Tests: Ensuring Isolation and Removing Voodoo Sleeps
6.1 Ensuring Test Isolation in Functional Tests
- Problem left on scratchpad: Clean up after FT runs
- Methods:
-
- In
functional_tests.py
add in codes to delete database
- In
-
- Use class
LiveServerTestCase
(Django 1.4). It will create a test db and start up a dev server for functional tests
- Use class
-
How to use LiveServerTestCase
:
- It's derived from Django's
TestCase
class, so can be run by Django test runner - Django test runner search for all scripts start with
test
What to do?:
- Create a
functional_test
directory, i.e. create a functional_test app - rename
functional_test.py
astests.py
and move it intofunctional_test
directory - Modify
tests.py
to let it useLiveServerTestCase
as shown below, and instead of hardcoding visit to localhost port 8000,LiveserverTestCase
provide attributelive_server_url
.
class NewVisitorTest(LiveServerTestCase):
...
def test_can_start_a_list_and_retrieve_it_later(self):
# Edith has heard about a cool new online to-do app. She goes
# to check out its homepage
self.browser.get(self.live_server_url)
6.1.1 Running Just the Unit Tests
We can specify what we want to run by
python manage.py test functional_tests
or
python manage.py test lists
6.2 Aside: Upgrading Selenium and Geckodriver
Sometimes, mismatch between firefox and (Selenium + Geckodriver) may result failure in test, as firefox may auto upgrade itself at night. Upgrade Selenium + Geckodriver as follow:
pip install --upgrade selenium
- Download new geckodriver
6.3 On Implicit and Explicit Waits, and Voodoo time.sleeps
Implicit Waits & Explicit Waits:
- Implicit Waits: Selenium tries to wait "automatically" for you when it thinks the page is loading. But it's unstable, DON'T USE IT.
- Explicit Waits:
time.sleep(...)
in FT. It's hard to set a fixed second (Voodoo Sleep). A while loop with try/except will be more better
from selenium.common.exceptions import WebDriverException
MAX_WAIT = 10 # Maximum amount of time we're prepared to wait
[...]
def wait_for_row_in_list_table(self, row_text):
start_time = time.time()
while True:
try:
table = self.browser.find_element_by_id('id_list_table')
rows = table.find_elements_by_tag_name('tr')
self.assertIn(row_text, [row.text for row in rows])
return
except (AssertionError, WebDriverException) as e:
if time.time() - start_time > MAX_WAIT:
raise e
time.sleep(0.5)
Replace all check_for_row_in_list_table
with wait_for_row_in_list_table
"BEST PRACTICES" Applied in this Chapter
- Ensuring test isolation and managing global state
- Avoid "voodoo" sleeps (i.e.
time.sleep
) - Don't rely on Selenium's implicit waits