如何在测试套件中并行执行测试

And*_*ist 5 python selenium python-multiprocessing

我已经成功通过使用 webdriver 针对 selenium 集线器和节点并行运行测试。该代码在测试运行之前调用。

cls.driver = webdriver.Remote(
   command_executor="http://localhost:4444/wd/hub",
   desired_capabilities={
        "browserName": "chrome",
        })

    cls.driver.maximize_window()
    cls.driver.get(cls.serverUrl)
    p = multiprocessing.Process(target=cls.driver.get(cls.serverUrl), args=())
    p.start()
    p.join()
Run Code Online (Sandbox Code Playgroud)

这样我就可以通过从 Eclipse 手动执行来启动多个浏览器。不过我想在测试套件中自动执行此操作。但在测试套件中,所有测试都是按顺序启动的。如果有人知道如何进行,那就太好了。

hoe*_*ing 6

预赛

我准备了一些示例测试来玩。这些是一些简单的页面标题检查。我们有一个包含两个单元测试的模块,用于检查和test_google.py的标题:www.google.commail.google.com

# test_google.py

import unittest
from selenium import webdriver


class GoogleTests(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Chrome()

    def tearDown(self):
        self.driver.close()


    def test_google_page_title(self):
        self.driver.get('https://www.google.com')
        assert self.driver.title == 'Google'

    def test_gmail_page_title(self):
        self.driver.get('https://mail.google.com')
        assert self.driver.title == 'Gmail'
Run Code Online (Sandbox Code Playgroud)

第二个模块test_stackoverflow.py包含一个测试,用于检查以下标题stackoverflow.com

# test_stackoverflow.py

import unittest
from selenium import webdriver


class StackoverflowTests(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Chrome()

    def tearDown(self):
        self.driver.close()


    def test_so_page_title(self):
        self.driver.get('https://stackoverflow.com')
        assert 'Stack Overflow' in self.driver.title
Run Code Online (Sandbox Code Playgroud)

使用裸运行器运行测试unittest会产生:

$ python setup.py test
running test
running egg_info
...
running build_ext
test_gmail_page_title (test_google.GoogleTests) ... ok
test_google_page_title (test_google.GoogleTests) ... ok
test_so_page_title (test_stackoverflow.StackoverflowTests) ... ok

----------------------------------------------------------------------
Ran 3 tests in 11.657s

OK
Run Code Online (Sandbox Code Playgroud)

迁移至pytest

pytest通过以下方式安装pip

$ pip install pytest
Run Code Online (Sandbox Code Playgroud)

pytest支持开箱即用的单元测试,因此我们不需要接触测试,我们可以立即运行它们。尝试pytest跑步者:

$ pytest -v
================ test session starts ================
platform darwin -- Python 3.6.3, pytest-3.2.5, py-1.5.2, pluggy-0.4.0 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-47439103, inifile:
collected 3 items                                                                                                                                                                                   

test_google.py::GoogleTests::test_gmail_page_title PASSED
test_google.py::GoogleTests::test_google_page_title PASSED
test_stackoverflow.py::StackoverflowTests::test_so_page_title PASSED

================ 3 passed in 13.81 seconds ================
Run Code Online (Sandbox Code Playgroud)

并行运行测试

这需要pytest-xdist插件pytest。通过以下方式安装pip

$ pip install pytest-xdist
Run Code Online (Sandbox Code Playgroud)

该插件现已安装,但默认情况下不会处于活动状态,因此如果pytest再次运行,您不会注意到任何差异。使用numprocesseskey 并行化测试执行。这表示为运行测试而保留的进程数,这里我使用该auto值来生成与我的机器具有的 CPU 数量一样多的进程:

$ pytest -v --numprocesses=auto
================ test session starts ================
platform darwin -- Python 3.6.3, pytest-3.2.5, py-1.5.2, pluggy-0.4.0 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-47439103, inifile:
plugins: xdist-1.20.1, forked-0.2
[gw0] darwin Python 3.6.3 cwd: /Users/hoefling/projects/private/stackoverflow/so-47439103
[gw1] darwin Python 3.6.3 cwd: /Users/hoefling/projects/private/stackoverflow/so-47439103
[gw2] darwin Python 3.6.3 cwd: /Users/hoefling/projects/private/stackoverflow/so-47439103
[gw3] darwin Python 3.6.3 cwd: /Users/hoefling/projects/private/stackoverflow/so-47439103
[gw0] Python 3.6.3 (v3.6.3:2c5fed86e0, Oct  3 2017, 00:32:08)  -- [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
[gw1] Python 3.6.3 (v3.6.3:2c5fed86e0, Oct  3 2017, 00:32:08)  -- [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
[gw2] Python 3.6.3 (v3.6.3:2c5fed86e0, Oct  3 2017, 00:32:08)  -- [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
[gw3] Python 3.6.3 (v3.6.3:2c5fed86e0, Oct  3 2017, 00:32:08)  -- [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
gw0 [3] / gw1 [3] / gw2 [3] / gw3 [3]
scheduling tests via LoadScheduling

test_google.py::GoogleTests::test_google_page_title 
test_stackoverflow.py::StackoverflowTests::test_so_page_title 
test_google.py::GoogleTests::test_gmail_page_title 
[gw0] PASSED test_google.py::GoogleTests::test_gmail_page_title 
[gw1] PASSED test_google.py::GoogleTests::test_google_page_title 
[gw2] PASSED test_stackoverflow.py::StackoverflowTests::test_so_page_title 

================ 3 passed in 7.81 seconds ================
Run Code Online (Sandbox Code Playgroud)

您将看到所有三个测试通过同时打开的三个 chrome 实例并行运行。每个测试都在自己的进程中运行,因此它们不会相互干扰。另请注意,GoogleTests类中的两个测试方法也并行运行,因此这不限于不同模块或类中的测试。

与集成setup.py

当我第一次开始迁移到 时pytest,我的条件之一是命令python setup.py test应该仍然有效,因此我们不需要记住额外的pytest命令来运行测试,因此我们也不必调整所有实用程序脚本或在我们的集成服务器上构建作业,因此以下是更新脚本的步骤setup.py

  1. 添加以下包来测试需求:

    from setuptools import setup
    
    setup(
        ...
        tests_require=[
            'pytest',
            'pytest-runner',  # this one is needed to install distutils command for pytest
            'pytest-xdist'
        ],
    )
    
    Run Code Online (Sandbox Code Playgroud)
  2. 添加别名setup.cfg

    [aliases]
    test=pytest
    
    Run Code Online (Sandbox Code Playgroud)
  3. pytest添加in的配置部分setup.cfg

    [tool:pytest]
    addopts=--verbose --numprocesses=auto
    
    Run Code Online (Sandbox Code Playgroud)

现在,如果您运行python setup.py test,将调用正确的运行器,并且xdist默认情况下该插件将处于活动状态。

补充笔记

我个人非常喜欢pytest,因为它提供的不仅仅是简单的测试执行 - 您可以将测试编写为纯函数(不需要包装到TestCase类中),收集测试而不执行它们,轻松地仅重新运行最近失败的测试,将代码覆盖率测量与不同格式的多个报告等等。更多细节请参考官方文档,非常值得花时间阅读!