Reputation: 1212
I'm struggling to setup my test runner for a new Django project. I want to use these libraries :
And I want it to work with Docker. I got a head start with that answer : https://stackoverflow.com/a/58447497/3219759 but I can't make it work.
Here is my docker-compose.yml
:
version: '3.3'
services:
web:
build: jam
restart: always
command: python manage.py runserver 0.0.0.0:8000
environment:
- USE_DOCKER=True
env_file:
- .env
ports:
- "127.0.0.1:8000:8000"
volumes:
- .:/code
links:
- db
depends_on:
- db
- selenium
db:
image: postgres
environment:
- POSTGRES_USER=xxx
- POSTGRES_PASSWORD=xxx
- POSTGRES_DB=xxx
ports:
- "127.0.0.1:5432:5432"
volumes:
- pg_data:/var/lib/postgresql/data
selenium:
image: selenium/standalone-firefox:4.9.1
ports:
- "4444:4444" # Selenium
- "5900:5900" # VNC
volumes:
pg_data:
And to finish the setup, I have these fixtures in the conftest.py
file :
@pytest.fixture(scope='session')
def test_server() -> LiveServer:
addr = socket.gethostbyname(socket.gethostname())
server = LiveServer(addr)
yield server
server.stop()
@pytest.fixture(scope='session')
def splinter_webdriver():
return 'remote'
@pytest.fixture(scope='session')
def splinter_remote_url():
return 'http://selenium:4444/wd/hub'
and this in settings.py
:
if env('USE_DOCKER') == 'yes':
import socket
ALLOWED_HOSTS = [socket.gethostbyname(socket.gethostname())]
I have a basic view that list all the profiles, and a template to match. This feature is working on my local server.
The corresponding test:
@pytest.mark.django_db
class TestIndexPage:
def test_profile_list(self, browser, test_server):
profile = ProfileFactory(description='first description')
browser.visit(test_server.url + reverse('index', current_app='Profiles'))
assert browser.is_text_present('first description') is True
The ProfileFactory is set up with factoryboy, and it seems to work fine.
I launch the test suite with
$ docker compose run --rm web pytest
And the test fails :
_______________________ TestIndexPage.test_profile_list ________________________
self = <profiles.tests.test_index.TestIndexPage object at 0x7fd3a15141a0>
browser = <splinter.driver.webdriver.remote.WebDriver object at 0x7fd3a0034680>
test_server = <LiveServer listening at http://172.31.0.4:49073>
def test_profile_list(self, browser, test_server):
profile1 = ProfileFactory(description='first description')
browser.visit(test_server.url + reverse('index', current_app='Profiles'))
> assert browser.is_text_present('first description') is True
E AssertionError: assert False is True
E + where False = <bound method BaseWebDriver.is_text_present of <splinter.driver.webdriver.remote.WebDriver object at 0x7fd3a0034680>>('first description')
E + where <bound method BaseWebDriver.is_text_present of <splinter.driver.webdriver.remote.WebDriver object at 0x7fd3a0034680>> = <splinter.driver.webdriver.remote.WebDriver object at 0x7fd3a0034680>.is_text_present
profiles/tests/test_index.py:13: AssertionError
Basically the test can't find the profile in the browser, the screenshot is confirming that with a 'no profiles yet' message on the page.
But when I setup a breakpoint there :
@pytest.mark.django_db
class TestIndexPage:
def test_profile_list(self, browser, test_server):
profile = ProfileFactory(description='first description')
breakpoint()
browser.visit(test_server.url + reverse('index', current_app='Profiles'))
assert browser.is_text_present('first description') is True
I can easily find the profile :
>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>
> /code/profiles/tests/test_index.py(11)test_profile_list()
-> browser.visit(test_server.url + reverse('index', current_app='Profiles'))
(Pdb) from profiles.models import Profile
(Pdb) Profile.objects.count()
1
(Pdb) Profile.objects.all()
<QuerySet [<Profile: george36>]>
So, factoryboy is generating a profile, which I can see with the breakpoint. But this data is not shown in the browser generated by selenium, and the test fails.
There must be something wrong in the Docker setup, feels like there is two test databases, one used by selenium and the other by pytest. There is a bad connection somewhere.
Just found this message in the pytest warnings that are displayed after the failure :
profiles/tests/test_index.py::TestIndexPage::test_profile_list
/code:0: PytestWarning: Error when trying to teardown test databases:
OperationalError('database "test_tutorial" is being accessed by other users\nDETAIL: There is 1 other session using the database.\n')
Upvotes: 1
Views: 128
Reputation: 1212
Thanks to @mariodev comment, I found a way to make it work.
I used this basic mark with my test :
@pytest.mark.django_db
I finally made it work with the transactional option :
@pytest.mark.django_db(transaction=True)
Upvotes: 1