使用unittest编写测试
1. unittest库简介
在自动化测试的世界里,unittest
是一个非常强大的库,它可以帮助开发者编写可靠的测试用例。unittest
是 Python 自带的标准库之一,灵感来源于 Java 的 JUnit,旨在为开发者提供一种简单而有效的方式来编写和运行测试。
1.1 unittest库的作用
unittest
提供了创建测试用例、测试套件、测试夹具(Fixture)等功能。通过 unittest
,我们可以轻松地编写测试代码,确保应用程序的正确性和稳定性。以下是 unittest
的几个核心功能:
- 测试用例(Test Case):最基本的测试单位,用于检查特定的操作和输入是否产生预期的结果。
- 测试套件(Test Suite):一组测试用例的集合,用于将多个测试组织在一起并批量运行。
- 测试夹具(Test Fixture):用于定义测试前后的准备工作和清理工作,确保每个测试都在相同的环境中运行。
- 测试运行器(Test Runner):负责协调测试的执行,并向用户提供测试结果。
1.2 unittest库的安装
由于 unittest
是 Python 的标准库之一,因此无需额外安装。只要你的环境中已经安装了 Python,就可以直接使用 unittest
。
2. 使用TestCase类构建测试用例
TestCase
类是 unittest
中的核心类,所有的测试用例都应该是 TestCase
的子类。通过继承 TestCase
类,我们可以方便地编写测试方法,并使用 unittest
提供的各种断言方法来验证测试结果。
2.1 创建TestCase类
下面是一个简单的例子,展示了如何创建一个继承自 TestCase
的测试类,并编写测试方法:
import unittest
from selenium import webdriver
class SearchTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
# 创建一个新的Firefox会话
cls.driver = webdriver.Firefox()
cls.driver.implicitly_wait(30)
cls.driver.maximize_window()
# 导航至应用程序主页
cls.driver.get("http://demo.magentocommerce.com/")
cls.driver.title
def test_search_by_category(self):
# 获取搜索文本框
self.search_field = self.driver.find_element_by_name("q")
self.search_field.clear()
# 输入搜索关键词并提交
self.search_field.send_keys("手机")
self.search_field.submit()
# 获取所有包含产品名称的锚点元素
products = self.driver.find_elements_by_xpath("//h2[@class='product-name']/a")
self.assertEqual(2, len(products))
@classmethod
def tearDownClass(cls):
# 关闭浏览器窗口
cls.driver.quit()
if __name__ == '__main__':
unittest.main()
2.2 使用setUp()
方法
setUp()
方法用于在每个测试方法执行之前设置测试环境。它可以用来初始化测试所需的资源,例如创建浏览器实例、加载测试数据等。setUp()
方法在每个测试方法执行之前都会被调用一次。
def setUp(self):
# 创建一个新的Firefox会话
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.driver.maximize_window()
# 导航至应用程序主页
self.driver.get("http://demo.magentocommerce.com/")
2.3 使用tearDown()
方法
tearDown()
方法用于在每个测试方法执行之后清理测试环境。它可以用来释放测试过程中占用的资源,例如关闭浏览器窗口、删除临时文件等。tearDown()
方法在每个测试方法执行之后都会被调用一次。
def tearDown(self):
# 关闭浏览器窗口
self.driver.quit()
3. 编写测试代码
在编写测试代码时,我们需要确保每个测试用例都能独立运行,并且不会相互影响。为了实现这一点,unittest
提供了一系列的断言方法,用于验证测试结果是否符合预期。
3.1 使用断言方法
unittest
提供了多种断言方法,用于验证测试结果。常用的断言方法包括:
断言方法 | 描述 |
---|---|
assertEqual(a, b) | 检查 a 是否等于 b |
assertTrue(x) | 检查 x 是否为 True |
assertFalse(x) | 检查 x 是否为 False |
assertIn(a, b) | 检查 a 是否在 b 中 |
assertRaises(exception, callable, *args, **kwargs) | 检查 callable(*args, **kwargs) 是否抛出指定的异常 |
3.2 示例:编写测试代码
下面是一个完整的测试代码示例,展示了如何使用 unittest
和 Selenium
来编写测试用例:
import unittest
from selenium import webdriver
class SearchTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
# 创建一个新的Firefox会话
cls.driver = webdriver.Firefox()
cls.driver.implicitly_wait(30)
cls.driver.maximize_window()
# 导航至应用程序主页
cls.driver.get("http://demo.magentocommerce.com/")
cls.driver.title
def test_search_by_category(self):
# 获取搜索文本框
self.search_field = self.driver.find_element_by_name("q")
self.search_field.clear()
# 输入搜索关键词并提交
self.search_field.send_keys("手机")
self.search_field.submit()
# 获取所有包含产品名称的锚点元素
products = self.driver.find_elements_by_xpath("//h2[@class='product-name']/a")
self.assertEqual(2, len(products))
def test_search_by_name(self):
# 获取搜索文本框
self.search_field = self.driver.find_element_by_name("q")
self.search_field.clear()
# 输入搜索关键词并提交
self.search_field.send_keys("salt shaker")
self.search_field.submit()
# 获取所有包含产品名称的锚点元素
products = self.driver.find_elements_by_xpath("//h2[@class='product-name']/a")
self.assertEqual(1, len(products))
@classmethod
def tearDownClass(cls):
# 关闭浏览器窗口
cls.driver.quit()
if __name__ == '__main__':
unittest.main()
4. 运行测试用例
编写完测试用例后,我们需要运行这些测试用例,并分析测试结果。unittest
提供了多种方式来运行测试用例,最常见的是通过命令行或直接在代码中调用 unittest.main()
方法。
4.1 使用命令行运行测试
如果你将测试代码保存在一个 .py
文件中,可以直接在命令行中运行该文件。例如,如果你的测试文件名为 test_search.py
,可以在命令行中执行以下命令:
python test_search.py
4.2 使用unittest.main()
方法运行测试
在测试代码的末尾添加 unittest.main()
方法,可以直接在 Python 脚本中运行测试:
if __name__ == '__main__':
unittest.main()
4.3 分析测试结果
运行测试后,unittest
会在控制台中输出测试结果。每个测试用例的结果可能是 OK
或 FAIL
。对于失败的测试用例,unittest
会显示详细的错误信息,帮助开发者快速定位问题。
5. 类级别的setUp()
和tearDown()
方法
除了每个测试方法的 setUp()
和 tearDown()
方法外,unittest
还提供了类级别的 setUpClass()
和 tearDownClass()
方法。这些方法用于在所有测试方法执行之前和之后执行一次性的设置和清理工作。
5.1 使用setUpClass()
方法
setUpClass()
方法用于在所有测试方法执行之前设置测试环境。它可以用来初始化只在测试类中共享的资源,例如创建一个浏览器实例并保持在整个测试类中使用。
@classmethod
def setUpClass(cls):
# 创建一个新的Firefox会话
cls.driver = webdriver.Firefox()
cls.driver.implicitly_wait(30)
cls.driver.maximize_window()
# 导航至应用程序主页
cls.driver.get("http://demo.magentocommerce.com/")
cls.driver.title
5.2 使用tearDownClass()
方法
tearDownClass()
方法用于在所有测试方法执行之后清理测试环境。它可以用来释放测试过程中占用的资源,例如关闭浏览器窗口。
@classmethod
def tearDownClass(cls):
# 关闭浏览器窗口
cls.driver.quit()
5.3 类级别方法的优势
使用类级别的 setUpClass()
和 tearDownClass()
方法可以减少资源的重复创建和销毁,从而提高测试效率。尤其是在需要频繁创建和销毁浏览器实例的情况下,类级别的方法可以显著提升性能。
6. 测试套件(Test Suite)
为了更好地组织和管理测试用例,unittest
提供了测试套件(Test Suite)的概念。测试套件可以将多个测试用例组织在一起,并作为一个整体运行。
6.1 创建测试套件
可以通过 unittest.TestLoader().loadTestsFromTestCase()
方法将多个测试用例加载到测试套件中:
import unittest
from searchtests import SearchTests
from homapagetest import HomePageTest
# 获取所有测试用例
search_tests = unittest.TestLoader().loadTestsFromTestCase(SearchTests)
home_page_tests = unittest.TestLoader().loadTestsFromTestCase(HomePageTest)
# 创建测试套件
smoke_tests = unittest.TestSuite([home_page_tests, search_tests])
6.2 运行测试套件
创建完测试套件后,可以使用 unittest.TextTestRunner()
来运行测试套件:
if __name__ == '__main__':
unittest.TextTestRunner(verbosity=2).run(smoke_tests)
6.3 测试套件的优势
使用测试套件可以将多个测试用例组织在一起,便于批量运行和管理。这对于大型项目来说尤为重要,因为它可以帮助开发者更高效地管理和执行大量的测试用例。
7. 生成HTML测试报告
虽然 unittest
提供了控制台输出的测试结果,但在实际项目中,我们通常需要生成格式良好的测试报告,以便于向项目各利益相关者分发和展示测试结果。
7.1 使用HTMLTestRunner生成HTML报告
HTMLTestRunner
是一个第三方库,可以生成美观的 HTML 测试报告。你可以通过以下步骤安装和使用 HTMLTestRunner
:
-
安装HTMLTestRunner:
你可以通过pip
安装HTMLTestRunner
:pip install html-testRunner
-
修改测试代码:
修改测试代码,使用HTMLTestRunner
生成 HTML 报告:
import unittest
import os
from HtmlTestRunner import HTMLTestRunner
from searchtests import SearchTests
from homapagetest import HomePageTest
# 获取输出报告文件的目录路径
dir = os.getcwd()
# 获取所有测试用例
search_tests = unittest.TestLoader().loadTestsFromTestCase(SearchTests)
home_page_tests = unittest.TestLoader().loadTestsFromTestCase(HomePageTest)
# 创建测试套件
smoke_tests = unittest.TestSuite([home_page_tests, search_tests])
# 打开报告文件
outfile = open(dir + "\SmokeTestReport.html", "w")
# 配置 HTMLTestRunner 选项
runner = HTMLTestRunner.HTMLTestRunner(
stream=outfile,
title='测试报告',
description='冒烟测试'
)
# 使用 HTMLTestRunner 运行测试套件
runner.run(smoke_tests)
7.2 HTML报告的优势
HTML 报告不仅格式美观,而且提供了详细的测试结果信息,包括每个测试用例的执行结果、失败原因等。这对于项目的长期维护和团队协作非常有帮助。
通过以上内容,我们已经掌握了如何使用 unittest
结合 Selenium
来编写和运行自动化测试的基本技能。接下来,我们将进一步探讨如何使用 unittest
的高级功能,例如数据驱动测试和页面对象模式,来提升测试的可维护性和效率。
表格:常用断言方法
断言方法 | 描述 |
---|---|
assertEqual(a, b) | 检查 a 是否等于 b |
assertTrue(x) | 检查 x 是否为 True |
assertFalse(x) | 检查 x 是否为 False |
assertIn(a, b) | 检查 a 是否在 b 中 |
assertRaises(exception, callable, *args, **kwargs) | 检查 callable(*args, **kwargs) 是否抛出指定的异常 |