前言

本节将介绍如何结合 unittest 进行自动化测试,以及使用 Page Object 设计模式提高测试代码的可维护性。

知识点

  • 结合 unittest 进行测试

  • 测试用例的编写

  • Page Object 设计模式

  • 实例:使用 Page Object 设计模式编写测试用例

结合 unittest 进行测试

Unittest 是 Python 自带的单元测试框架,它可以帮助我们更好地组织测试代码,提高测试的可维护性。

Unittest 主要可以用于组织和执行测试用例,并提供了丰富的断言方法,可以用于判断测试结果是否符合预期。

Unittest 简介

Unittest 是 Python 的官方单元测试框架,主要由以下几个部分组成:

  • TestCase(测试用例): 定义了一个测试用例,包括测试环境的搭建(setUp)、测试用例的执行(test_*方法)、以及测试环境的还原(tearDown)。

  • TestSuite(测试套件): 将多个测试用例组织在一起,方便进行批量执行。

  • TestRunner(测试运行器): 控制测试用例的执行流程,输出测试结果。

  • TestFixture(测试夹具): 提供测试用例执行所需的一些资源或环境。

Unittest 的基本结构

一个基本的 Unittest 测试用例结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import unittest

class MyTestCase(unittest.TestCase):
def setUp(self):
# 在每个测试用例执行前的初始化操作
pass

def tearDown(self):
# 在每个测试用例执行后的清理操作
pass

def test_example(self):
# 具体的测试逻辑
self.assertEqual(1 + 1, 2)

if __name__ == '__main__':
unittest.main()

在这个例子中,MyTestCase 继承自 unittest.TestCase,并包含了 setUptearDown 和一个测试方法 test_example

Unittest 示例

以下是一个简单的 Unittest 测试用例示例,测试一个加法操作:

1
2
3
4
5
6
7
8
9
import unittest

class TestMathOperations(unittest.TestCase):
def test_addition(self):
result = 1 + 1
self.assertEqual(result, 2, "加法运算错误")

if __name__ == '__main__':
unittest.main()

这个测试用例包含了一个测试方法 test_addition,用于测试加法运算的正确性。

在这个示例中,使用了 self.assertEqual() 断言方法,用于判断 result 是否等于期望值 2。如果不相等,会输出断言错误信息 “加法运算错误”。

通过结合 Unittest 进行自动化测试,可以更好地组织测试代码,提高测试的可维护性。

测试用例的编写

通过上面简单的示例,我们已经了解了 Unittest 的基本结构,接下来我们将结合实际的测试场景,编写一个完整的 Selenium 测试用例。

步骤

  1. 导入必要的模块:
1
2
3
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
  1. 创建测试类,并在 setUp 方法中进行初始化操作,如启动浏览器和打开测试网页:
1
2
3
4
class TestLoginPage(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://selenium-app.im0o.top/login-example")
  1. 编写测试方法,验证登录功能。这里以输入用户名和密码,点击登录按钮为例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def test_login_success(self):
# 定位用户名和密码输入框,并输入信息
username_input = self.driver.find_element(By.ID, 'username')
password_input = self.driver.find_element(By.ID, 'password')
username_input.send_keys('admin')
password_input.send_keys('rootadmin')

# 定位登录按钮,并点击
login_button = self.driver.find_element(By.XPATH, '//*[@id="app"]/div/form/input[3]')
login_button.click()

# 验证登录成功后的页面是否正确
welcome_message = self.driver.find_element(By.ID, 'login-example-result')
self.assertEqual(welcome_message.text, '登录成功', "登录失败")
  1. tearDown 方法中进行清理操作,关闭浏览器:
1
2
3
def tearDown(self):
# 关闭浏览器
self.driver.quit()
  1. 运行测试用例:
1
2
if __name__ == '__main__':
unittest.main()

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By


class TestLoginPage(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://selenium-app.im0o.top/login-example")

def test_login_success(self):
# 定位用户名和密码输入框,并输入信息
username_input = self.driver.find_element(By.ID, 'username')
password_input = self.driver.find_element(By.ID, 'password')
username_input.send_keys('admin')
password_input.send_keys('rootadmin')

# 定位登录按钮,并点击
login_button = self.driver.find_element(By.XPATH, '//*[@id="app"]/div/form/input[3]')
login_button.click()

# 验证登录成功后的页面是否正确
welcome_message = self.driver.find_element(By.ID, 'login-example-result')
self.assertEqual(welcome_message.text, '登录成功', "登录失败")
def tearDown(self):
# 关闭浏览器
self.driver.quit()

if __name__ == '__main__':
unittest.main()

通过以上步骤,我们完成了一个简单的 Selenium 测试用例,用于验证登录页面的基本功能。

运行结果

通过 Pycharm 的测试运行器,可以看到测试用例的执行结果。

Page Object 设计模式

Page Object 设计模式是一种常用的测试设计模式,它将页面的元素和操作封装成一个对象,方便测试用例的编写和维护。

Page Object 设计模式的优势

  • 提高测试用例的可维护性: 将页面元素和操作封装成一个对象,方便测试用例的编写和维护。

  • 提高测试用例的复用性: 一个页面对应一个 Page Object 对象,可以在多个测试用例中复用。

  • 提高测试用例的可读性: 通过 Page Object 对象的方法名,可以直观地了解测试用例的执行逻辑。

Page Object 设计模式的实现

Page Object 设计模式的实现,主要包括以下几个步骤:

  1. 创建一个 Page Object 对象,用于封装页面元素和操作。

  2. 在测试用例中,实例化 Page Object 对象,并调用其中的方法。

实例:使用 Page Object 设计模式编写测试用例

在配套网页——实例:使用 Selenium 模拟用户登录 中,我们已经实现了一个简单的登录页面,现在我们将使用 Page Object 设计模式,编写一个测试用例,验证登录功能。

登录页面

登录页面包含以下元素:

元素 ID class name 备注
用户名输入框 username - username -
密码输入框 password - password -
登录按钮 - - - 使用 Xpath 或定位 input[type=”submit”]
登录成功提示 login-example-result login-example-result login-example-result -

Page Object 设计模式

Page Object 设计模式将页面的元素和操作封装在一个类中,以提高测试代码的可维护性。我们将创建一个 LoginPage 类,用于表示登录页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# login_page.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

class LoginPage:
def __init__(self, driver):
self.driver = driver
self.url = "https://selenium-app.im0o.top/login-example"
self.username_input = (By.ID, 'username')
self.password_input = (By.ID, 'password')
self.login_button = (By.XPATH, '//*[@id="app"]/div/form/input[3]')
self.result = (By.ID, 'login-example-result')
self.driver.implicitly_wait(10)

def open(self):
self.driver.get(self.url)

def input_username(self, username):
self.driver.find_element(*self.username_input).send_keys(username)

def input_password(self, password):
self.driver.find_element(*self.password_input).send_keys(password)

def click_login_button(self):
self.driver.find_element(*self.login_button).click()

def get_result(self):
wait = WebDriverWait(self.driver, 10)
wait.until(lambda driver: self.driver.find_element(*self.result))
return self.driver.find_element(*self.result).text

测试用例

使用 Page Object 设计模式编写的测试用例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import unittest
from selenium import webdriver
from login_page import LoginPage

class TestLoginPage(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.login_page = LoginPage(self.driver)
self.login_page.open()

def test_login_success(self):
self.login_page.input_username('admin')
self.login_page.input_password('rootadmin')
self.login_page.click_login_button()
result = self.login_page.get_result()
self.assertEqual(result, '登录成功', "登录失败")

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

if __name__ == '__main__':
unittest.main()

通过 Page Object 设计模式,我们将页面元素和操作封装在 LoginPage 类中,测试用例更加清晰和可维护。

运行结果

添加测试用例

Page Object 的优势在于,可以在多个测试用例中复用。我们可以在 TestLoginPage 类中,添加多个测试用例,验证登录页面的其他功能。

1
2
3
4
5
6
def test_login_failed(self):
self.login_page.input_username('admin')
self.login_page.input_password('123456')
self.login_page.click_login_button()
result = self.login_page.get_result()
self.assertEqual(result, '用户名或密码错误', "登录成功")

At last

头图/封面素材来源:Photo by Hal Gatewood on Unsplash