在 docker 中使用 selenium 运行 django 测试
Posted
技术标签:
【中文标题】在 docker 中使用 selenium 运行 django 测试【英文标题】:Running django tests with selenium in docker 【发布时间】:2015-12-01 05:23:16 【问题描述】:为了执行测试,我通常运行一个单独的容器:
docker-compose run --rm web /bin/bash
其中 web 是 django 的容器。我不时在 shell 中执行 py.test。
为了能够使用 django 从容器访问 selenium,并允许 selenium 容器中的浏览器访问 django 的 liveserver,我决定使用允许容器共享网络的“net”参数。所以我将它添加到 yml 中:
selenium:
image: selenium/standalone-firefox
net: "container:web"
不幸的是,这不起作用。我的 django 容器中没有看到 4444 端口。
只有当我指定一个自动生成的容器名称而不是 net:"container:web"
时,它才有效,例如 net:"container:project_web_run_1"
。
我也尝试使用 docker-compose up --no-deps
将 command
参数更改为 py.test functional_tests
而不是 docker-compose run --rm ....
,但这也不起作用。
这是在容器中使用 selenium 的权利吗?
【问题讨论】:
【参考方案1】:我刚刚为LiveServerTestCase
指定了host='web'
。这是我的工作解决方案。
test.py
from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
class FunctionalTestCase(LiveServerTestCase):
host = 'web'
def setUp(self):
self.browser = webdriver.Remote(
command_executor="http://selenium:4444/wd/hub",
desired_capabilities=DesiredCapabilities.FIREFOX
)
def test_user_registration(self):
self.browser.get(self.live_server_url)
self.assertIn('Django', self.browser.title)
def tearDown(self):
self.browser.close()
docker-compose.yml
version: '3'
services:
db:
image: postgres
web:
build: .
ports:
- "8000:8000"
depends_on:
- db
- selenium
selenium:
image: selenium/standalone-firefox
请记住,您必须在 docker 映像中安装 selenium
才能正常工作:
$ docker-compose exec web bash
> pip install selenium
...
> pip freeze > ../requirements.txt
> exit
$ ...
【讨论】:
【参考方案2】:对于任何运行 pytest 的人,可能还有 pytest-splinter(Selenium 包装器)
version: '3'
services:
db:
image: postgres
django:
build: .
ports:
- "8000:8000"
depends_on:
- db
- selenium
selenium:
image: selenium/standalone-firefox-debug:latest
ports:
- "4444:4444" # Selenium
- "5900:5900" # VNC
在您的根目录中定义一个 conftest.py 以使这些固定装置可用于您的所有测试
import socket
import pytest
from pytest_django.live_server_helper import LiveServer
@pytest.fixture(scope='session')
def test_server() -> LiveServer:
addr = socket.gethostbyname(socket.gethostname())
server = LiveServer(addr)
yield server
server.stop()
@pytest.fixture(autouse=True, scope='function')
def _test_server_helper(request):
"""
Configures test_server fixture so you don't have to mark
tests with @pytest.mark.django_db
"""
if "test_server" not in request.fixturenames:
return
request.getfixturevalue("transactional_db")
# Settings below here are exclusive to splinter,
# I'm just overriding the default browser fixture settings
# If you just use selenium, no worries, just take note of the remote url and use
# it wherever you define your selenium browser
@pytest.fixture(scope='session')
def splinter_webdriver():
return 'remote'
@pytest.fixture(scope='session')
def splinter_remote_url():
return 'http://selenium:4444/wd/hub'
不要忘记在配置文件中设置 ALLOWED_HOSTS:
if env('USE_DOCKER') == 'yes':
import socket
ALLOWED_HOSTS = [socket.gethostbyname(socket.gethostname())]
# or just
ALLOWED_HOSTS = ['*']
那就去测试吧!
from django.urls import reverse
def test_site_loads(browser, test_server):
browser.visit(test_server.url + reverse('admin:index'))
【讨论】:
您能否澄清test_server
指的是什么以及它如何进入test_site_loads(browser, test_server)
的范围?它似乎与 conftest.py 中的定义有关,但它如何到达您的最后一个测试文件?【参考方案3】:
在我的例子中,“web”容器只运行一个命令,即bash -c "sleep infinity"
。
然后,我以docker-compose up -d
开始整个堆栈。
然后,例如,我使用docker-compose exec web bash -c "cd /usr/src/app && tox"
。
这样,我的web
主机可以从selenium
访问,始终使用相同的名称。
使用docker-compose run web ...
每次都会生成新的(可预测的,但仍然是)主机名。
【讨论】:
【参考方案4】:这是我的做法。基本问题是 docker-compose run 会生成一个不同的主机名(project_container_run_x),其中 x 很难确定。我最终只是离开了IP地址。我还要确保 DEBUG 为 False,否则我会收到错误的请求。
我正在像这样使用 StaticLiveServerTestCase:
import os
import socket
os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = '0.0.0.0:8000'
class IntegrationTests(StaticLiveServerTestCase):
live_server_url = 'http://:8000'.format(
socket.gethostbyname(socket.gethostname())
)
def setUp(self):
settings.DEBUG = True
self.browser = webdriver.Remote(
command_executor="http://selenium:4444/wd/hub",
desired_capabilities=DesiredCapabilities.CHROME
)
def tearDown(self):
self.browser.quit()
super().tearDown()
def test_home(self):
self.browser.get(self.live_server_url)
我的 docker-compose 文件有这个用于 selenium 并扩展了 web 容器(运行 django 的地方)。端口 5900 对 VNC 开放。我喜欢将其隔离在 docker-compose.selenium.yml 之类的东西中
version: '2'
services:
web:
environment:
SELENIUM_HOST: http://selenium:4444/wd/hub
TEST_SELENIUM: 'yes'
depends_on:
- selenium
selenium:
image: selenium/standalone-chrome-debug
ports:
- "5900:5900"
我可以运行类似的测试
docker-compose run --rm web ./manage.py test
所以我的 Web 容器正在通过“selenium”主机访问 selenium。 Selenium 然后通过动态确定的 IP 地址访问 Web 容器。
另一个问题是使用“web”作为主机名很诱人。如果您的 docker-compose run 命令启动了一个单独的 Web 容器 - 这似乎可以工作。但是它不会使用您的测试数据库,因此不是一个很好的测试。
【讨论】:
您也可以在环境中设置liveserver URL,这样您就不必每次都在命令行中传递它,方法是设置DJANGO_LIVE_TEST_SERVER_ADDRESS
。以上是关于在 docker 中使用 selenium 运行 django 测试的主要内容,如果未能解决你的问题,请参考以下文章
如何录制在 docker 内无头运行的 selenium 测试?
在docker-compose中运行python selenium
Docker selenium 自动化 - 使用python操作docker,python运行启用停用和查询容器实例演示