使用 python 和 selenium 做浏览器兼容测试

在进行web端测试的时候,为了保证网站能在不同的浏览器都有一个良好的表现,我们通常会进行浏览器的兼容测试。浏览器兼容测试的工具非常非常多,比如说大名鼎鼎的 browserling。但是在自动化测试中如何实现浏览器的兼容测试,却没有太多的参考教程,绝大多数的教程都是介绍几个selenium的API,然后就让你自己去拓展,丝毫没有提到通过不同的浏览器运行自动化测试代码的问题。

那么,同一套自动化测试的代码,能不能通过简单的配置,就能启动不同的浏览器分别进行测试呢?我写了几个简单的demo,证实通过一些简单的配置是可以做到浏览器兼容测试的,下面我把具体的过程分享出来。

1. 测试

首先我们需要选定一门编程语言和测试框架。我们就使用Python语言的pytest进行测试,然后使用selenium这个工具去控制浏览器的运行。因为每一个测试用例,我们都需要开启和关闭浏览器,所以开关浏览器的动作可以设置成前置条件(Setup)和后置清理(Teardown),在pytest的这个框架当中,我们使用夹具(fixture)实现浏览器的开关。

# content of conftest.py
from selenium import webdriver

@pytest.fixture()
def browser():
    driver = webdriver.Chrome()
    yield driver
    driver.quit()

在一个 conftest.py 的文件当中,我们定义一个browser夹具。夹具在本质上来说是一个函数,我们只需要在这个函数名上面加一个装饰器,声明这是一个夹具就可以了。在函数当中,通过 yield 返回浏览器对象,业务的之前的就是前置条件,必要的之后的就是后置清理。

在这个例子当中,yield之前启动一个浏览器,yield之后关掉浏览器。

注意:夹具放到conftest.py这个文件当中,换成其他的文件名是不可以的。

准备好夹具以后,开始编写测试用例。为了方便说明,在测试用例当中,我们只做一件事情,就是打开一个网页。

def test_demo(browser):
    browser.get("http://www.baidu.com")

测试用例是一个以test_开头的函数,这个函数的参数就是我们前面定义好的测试夹具。在执行测试用例函数之前, 程序会先调用测试夹具得到一个浏览器,在测试用例函数执行之后,测试夹具会把浏览器关掉。

现在我们可以直接在文件下通过pytest命令运行测试用例,此时你可以看到一个谷歌浏览器打开并访问了页面。

image-20210105171355732

2. 参数化实现兼容测试

但是现在这个测试夹具不能满足要求,因为它只初始化了一个chrome浏览器,并不能动态的改成其他浏览器。而测试夹具函数当中,我们是不能随意传参数的。但是要实现浏览器的兼容测试,必须每次运行browser测试夹具时动态传递浏览器名称。

image-20210105171607881

实现的第一种方式是通过夹具的参数化。 实现了夹具参数化以后,每次程序先会用其中的一个参数运行所有的测试用例,再换成其他的参数运行用例。

from selenium import webdriver

browsers = {
    "firefox": webdriver.Firefox,
    "chrome": webdriver.Chrome,
}

@pytest.fixture(params=browsers.keys())
def browser(request):
    browser_name = request.param
    driver = browsers.get(browser_name)()
    yield driver
    driver.quit()

在这里例子中,我们先把浏览器的名称和要调用的webdriver对象绑定在一起,存在browsers这个字典当中。 然后通过params参数获取broswer.keys(), 也就是所有可以使用的浏览器的名称。当程序运行以后,会自动先使用firefox名称,启动火狐浏览器运行测试用例,再换成chrome浏览器运行用例。如果还有更多的浏览器需要测试兼容性,只需要把他们添加browsers当中。

3. 命令行指定浏览器

在上面的例子中,所有的浏览器都被提前配置到 browsers 变量当中,在运行自动化测试脚本后,所有的浏览器都会依次执行。但是有时候我们并不想这么干。我们就想指定浏览器去跑,又不想频繁修改代码,最省心的方式就是配置一个命令行参数。

pytest要自定义命令行参数非常的简单,只需要在pytest_addoption这个钩子函数中添加命令行参数就可以, 这个钩子函数会收集所有的选项,把值保存到config当中。现在我们给 pytest 自定义一个--browser的命令行参数:

def pytest_addoption(parser):
    parser.addoption(
        "--browser",
        action="store",
        metavar="browsername",
        default=None,
        help="config the browser to run",
    )

配置好命令行参数以后,就可以在运行pytest的时候指定哪个浏览器运行了:

pytest --browser=chrome

但是现在如果直接运行的话,程序是无法根据你的参数去运行对应的浏览器的。还要改写browser测试夹具,从config当中获取浏览器名称:

browsers = {
    "firefox": webdriver.Firefox,
    "chrome": webdriver.Chrome,
}

@pytest.fixture()
def browser(pytestconfig):
    browser_name = pytestconfig.getoption('browser')
    if browser_name not in browsers:
        raise ValueError(f"browser {browser_name} not supported")
    driver = browsers.get(browser_name)()
    yield driver
    driver.quit()

pytestconfig是pytest自带的测试夹具,可以作为参数放到其他的家具当中,它的作用是获取所有的配置信息。当通过命令行输入浏览器名称以后,就被保存到了pytestconfig这个夹具当中,我们要做的就是通过pytestconfig.getoption("browser") 获取broswser这个命令行参数的值,然后去调用对应的浏览器。

文献

https://www.infoq.cn/article/lgrzzui5ee3sne2ntvjw