10.1生成测试用例
10.1.1 申请生成登录测试用例
产品登录页面如下:
代码语言:javascript
复制
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="../css/index.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/core.js"></script> <script src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/sha256.js"></script> <title>登录页面</title> <script src="../js/index.js" type="text/javascript"></script> </head> <body> <div class="container"> <h2>登录</h2> <form id="loginForm" name="loginForm" method="POST" action="login.jsp" onsubmit="return validateLoginForm();"> <input type="hidden" id="csrftoken" name="csrftoken" value="vRB6kNVanUDbT8g5b1bMY3fx6eoHXJhHiStsDc8EyAdTx2BkHrFCIXavHSA2ss6u6eZUMYLvH4pJmxCAGcpWWUguwme7AXy6NkTk"> <div> <label for="username">用户名:</label> <input type="text" id="username" name="username" placeholder="输入账号" required> <div id="usernameError" class="error"></div> </div> <div> <label for="password">密码:</label> <input type="password" id="password" name="password" placeholder="输入密码" required> <div id="passwordError" class="error"></div> </div> <button type="submit">登录</button> </form> <div id="loginError" class="error"> </div> </div> </body> </html>
登录页面界面包括。
l账号:文本框,5-20位大小写英文字符、数字。重复的账户不允许注册
l密码:密码框,必须包括大小写英文字符、数字和特殊字符,5-30位,SHA256散列传输。
登录成功出现“登录XXXX系统”提示。
登录失败,出现“用户名或密码错误“。
避免XSS注入
避免CSRF注入
避免SQL注入
不登录,直接在浏览器地址栏粘贴登录后地址,返回登录页面。
请设计测试用例。
10.1.2 生成登录测试用例回复
以下是针对产品登录页面的测试用例设计,涵盖了功能性、边界情况和安全性等方面的测试:
测试用例设计
1)功能性测试
用例ID |
测试内容 |
输入数据 |
预期结果 |
TC-001 |
验证有效用户名和密码登录 |
用户名: validUser |
登录成功,显示“登录XXXX系统”提示 |
TC-002 |
验证无效用户名登录 |
用户名: invalidUser |
显示“用户名或密码错误” |
TC-003 |
验证无效密码登录 |
用户名: validUser, 密码: wrongPassword |
显示“用户名或密码错误” |
TC-004 |
验证空用户名登录 |
用户名: ""密码: validPassword |
显示“用户名或密码错误” |
TC-005 |
验证空密码登录 |
用户名: validUser密码: "" |
显示“用户名或密码错误” |
TC-006 |
验证用户名长度边界 |
用户名: "a"(1个字符) |
显示“用户名长度不符合要求” |
TC-007 |
验证密码长度边界 |
密码: "123"(3个字符) |
显示“密码长度不符合要求” |
2)边界情况测试
用例ID |
测试内容 |
输入数据 |
预期结果 |
TC-008 |
验证用户名最大长度 |
用户名: "validUser123456789012345" |
登录成功,显示“登录XXXX系统”提示 |
TC-009 |
验证用户名最小长度 |
用户名: "user" |
登录成功,显示“登录XXXX系统”提示 |
TC-010 |
验证密码最大长度 |
密码: "ValidPassword123!"(30个字符) |
登录成功,显示“登录XXXX系统”提示 |
TC-011 |
验证密码最小长度 |
密码: "P@ss1" |
登录成功,显示“登录XXXX系统”提示 |
3)安全性测试
用例ID |
测试内容 |
输入数据 |
预期结果 |
TC-012 |
验证XSS注入 |
用户名: " <> alert('XSS') " |
显示“用户名或密码错误” |
TC-013 |
验证CSRF保护 |
模拟CSRF攻击 |
登录失败,显示“用户名或密码错误” |
TC-014 |
验证SQL注入 |
用户名: "admin' --" |
显示“用户名或密码错误” |
4)重定向测试
用例ID |
测试内容 |
输入数据 |
预期结果 |
TC-015 |
验证未登录用户访问登录后地址 |
直接访问: "/dashboard" |
重定向回登录页面 |
备注
测试用例中涉及的“有效用户名”和“有效密码”需要根据系统的实际注册情况进行定义。
安全性测试用例需要在安全测试环境中进行,以避免对生产环境造成影响。
测试用例的执行结果应记录实际结果与预期结果的对比,确保功能的正确性和安全性。
10.1.3 更新测试用例
假设存在一个账户,用户名:validUser,密码:ValidPassword123!。
1)功能性测试
用例ID |
测试内容 |
输入数据 |
预期结果 |
TC-001 |
验证有效用户名和密码登录 |
用户名: validUser密码:ValidPassword123! |
登录成功,显示“登录XXXX系统”提示 |
TC-002 |
验证无效用户名登录 |
用户名: invalidUser密码:ValidPassword123! |
显示“用户名或密码错误” |
TC-003 |
验证无效密码登录 |
用户名: validUser, 密码: wrongPassword |
显示“用户名或密码错误” |
TC-004 |
验证空用户名登录 |
用户名: ""密码: validPassword |
显示“账号必须是5-20位字母或数字” |
TC-005 |
验证空密码登录 |
用户名: validUser密码: "" |
显示“用户名或密码错误” |
TC-006 |
验证用户名长度边界 |
用户名: "a"(1个字符) |
显示“账号必须是5-20位字母或数字” |
TC-007 |
验证密码长度边界 |
密码: "123"(3个字符) |
显示“密码必须包含大小写字母、数字和特殊字符,长度在5-30之间” |
TC-001、TC-002、TC-003、TC-004、TC-005、TC-005:用API测试用例实现。
TC-006、TC-007:用GUI测试用例实现。
2)边界情况测试
用例ID |
测试内容 |
输入数据 |
预期结果 |
TC-008 |
验证用户名最大长度 |
用户名: "validUser12345678900" |
登录成功,显示“登录XXXX系统”提示 |
TC-009 |
验证用户名最小长度 |
用户名: "user1" |
登录成功,显示“登录XXXX系统”提示 |
TC-010 |
验证密码最大长度 |
密码: "ValidPassword1234567890123456!"(30个字符) |
登录成功,显示“登录XXXX系统”提示 |
TC-011 |
验证密码最小长度 |
密码: "P@ss1" |
登录成功,显示“登录XXXX系统”提示 |
所以测试用例均用API测试用例实现。
3)安全性测试
用例ID |
测试内容 |
输入数据 |
预期结果 |
TC-012 |
验证XSS注入 |
用户名: " <> alert('XSS') " |
显示“账号必须是5-20位字母或数字” |
TC-013 |
验证CSRF保护 |
模拟CSRF攻击 |
登录失败,显示“ ” |
TC-014 |
验证SQL注入 |
用户名: "admin' --" |
显示“账号必须是5-20位字母或数字” |
所以测试用例均用API测试用例实现。
4)重定向测试
用例ID |
测试内容 |
输入数据 |
预期结果 |
TC-015 |
验证未登录用户访问登录后地址 |
登录,然后登出,直接访问: "/welcome.jsp" |
重定向回登录页面 |
所以测试用例均用GUI测试用例实现。
10.2 生成登录API测试用例
10.2.1 申请登录API测试用例
生成如下的基于Python requests类+unittest框架的API测试用例脚本。
TC-001,验证有效用户名和密码登录,用户名: validUser,密码:ValidPassword123!,登录成功,显示“登录XXXX系统”提示。
TC-002,验证无效用户名登录,用户名: invalidUser,密码:ValidPassword123!,显示“用户名或密码错误”。
TC-003,验证无效密码登录,用户名: validUser, 密码: wrongPassword,显示“用户名或密码错误”。
TC-004,验证空用户名登录,用户名: "",密码: validPassword ,显示“账号必须是5-20位字母或数字”。
TC-005,验证空密码登录,用户名: validUser,密码: "",显示“密码应该哈希进行存储”。
TC-008,验证用户名最大长度,用户名: "validUser123456789012345",登录成功,显示“登录XXXX系统”提示。
TC-009,验证用户名最小长度,用户名: "user1",登录成功,显示“登录XXXX系统”提示。
TC-010,验证密码最大长度,密码: "ValidPassword1234567890123456!"(30个字符),登录成功,显示“登录XXXX系统”提示。
TC-011,验证密码最小长度,密码: "P@ss1",登录成功,显示“登录XXXX系统”提示。
TC-012,验证XSS注入,用户名: " <> alert('XSS') " ,显示“用户名或密码错误”。
TC-013,验证CSRF保护,模拟CSRF攻击,登录失败,显示“用户名或密码错误”。
TC-014,验证SQL注入,用户名: "admin' --" ,显示“用户名或密码错误”。
10.2.2登录API测试用例回复
下面是一个基于Python requests 类和 unittest 框架的API测试用例脚本,涵盖您提供的所有测试用例。请确保在运行此脚本之前,您已安装了 requests 库,并将相应的URL和响应内容替换为您实际使用的API。
代码语言:javascript
复制
import requests import unittest # 基础URL BASE_URL = "http://your-api-url.com/login" # 替换为实际的登录API URL WELCOME_URL = "http://your-api-url.com/welcome.jsp" # 替换为实际的受保护页面URL class TestLoginAPI(unittest.TestCase): def test_valid_login(self): response = requests.post(BASE_URL, data={'username': "validUser", 'password': "ValidPassword123!"}) self.assertEqual(response.json().get('message'), "登录XXXX系统") def test_invalid_username(self): response = requests.post(BASE_URL, data={'username': "invalidUser", 'password': "ValidPassword123!"}) self.assertEqual(response.json().get('message'), "用户名或密码错误") def test_invalid_password(self): response = requests.post(BASE_URL, data={'username': "validUser", 'password': "wrongPassword"}) self.assertEqual(response.json().get('message'), "用户名或密码错误") def test_empty_username(self): response = requests.post(BASE_URL, data={'username': "", 'password': "validPassword"}) self.assertEqual(response.json().get('message'), "账号必须是5-20位字母或数字") def test_empty_password(self): response = requests.post(BASE_URL, data={'username': "validUser", 'password': ""}) self.assertEqual(response.json().get('message'), "密码应该哈希进行存储") def test_username_max_length(self): response = requests.post(BASE_URL, data={'username': "validUser123456789012345", 'password': "ValidPassword123!"}) self.assertEqual(response.json().get('message'), "登录XXXX系统") def test_username_min_length(self): response = requests.post(BASE_URL, data={'username': "user1", 'password': "ValidPassword123!"}) self.assertEqual(response.json().get('message'), "登录XXXX系统") def test_password_max_length(self): response = requests.post(BASE_URL, data={'username': "validUser", 'password': "ValidPassword1234567890123456!"}) self.assertEqual(response.json().get('message'), "登录XXXX系统") def test_password_min_length(self): response = requests.post(BASE_URL, data={'username': "validUser", 'password': "P@ss1"}) self.assertEqual(response.json().get('message'), "登录XXXX系统") def test_xss_injection(self): response = requests.post(BASE_URL, data={'username': " <> alert('XSS') ", 'password': "ValidPassword123!"}) self.assertEqual(response.json().get('message'), "用户名或密码错误") def test_csrf_protection(self): # 假设CSRF令牌是必需的,这里我们不提供CSRF令牌 response = requests.post(BASE_URL, data={'username': "validUser", 'password': "ValidPassword123!"}) self.assertEqual(response.json().get('message'), "用户名或密码错误") def test_sql_injection(self): response = requests.post(BASE_URL, data={'username': "admin' --", 'password': "ValidPassword123!"}) self.assertEqual(response.json().get('message'), "用户名或密码错误") if __name__ == "__main__": unittest.main()
10.2.3调整登录API测试程序
1)修改Util.py
代码语言:javascript
复制
import pymysql import re import hashlib class ClassDB: #初始化数据库连接 def initDB(self): host = 'localhost' user = 'root' password = '123456' database = 'ebusiness' # 创建数据库连接 connection = pymysql.connect(host=host, user=user, password=password, database=database) return connection # 关闭数据库连接 def closedb(self,connection): connection.close() # 清空数据库user表中数据,用于DearDown def init_db(self): connection = self.initDB() try: with connection.cursor() as cursor: # SQL语句,用于清空user表 sql = "TRUNCATE TABLE user" # 执行SQL语句 cursor.execute(sql) # 提交事务 connection.commit() finally: self.closedb(connection) #为登录初始化数据 def init_login(self): connection = self.initDB() try: with connection.cursor() as cursor: password = HASH.hash_password("ValidPassword123!") # SQL语句,用于清空user表 sql = "INSERT INTO user (username, password, phone, email) VALUES (\"validUser\",\""+password+"\", \"13611223344\", \"a@b.com\")" # 执行SQL语句 cursor.execute(sql) # 提交事务 connection.commit() finally: self.closedb(connection) #建立特定用户名的user数据,密码为默认“ValidPassword123!” def login_for_name(self,username): connection = self.initDB() try: with connection.cursor() as cursor: password = HASH.hash_password("ValidPassword123!") # SQL语句,用于清空user表 sql = "INSERT INTO user (username, password, phone, email) VALUES (\""+username+"\",\""+password+"\", \"13611223344\", \"a@b.com\")" # 执行SQL语句 cursor.execute(sql) # 提交事务 connection.commit() finally: self.closedb(connection) #建立特定密码的user数据,用户名为默认“validUser” def login_for_password(self,password): connection = self.initDB() try: with connection.cursor() as cursor: password = HASH.hash_password(password) # SQL语句,用于清空user表 sql = "INSERT INTO user (username, password, phone, email) VALUES (\"validUser\",\""+password+"\", \"13611223344\", \"a@b.com\")" # 执行SQL语句 cursor.execute(sql) # 提交事务 connection.commit() finally: self.closedb(connection) class CSRF: def get_csrf(html): pattern = r'input[^>]+value="([^"]+)"' # 使用 re.search 查找匹配 match = re.search(pattern, html) # 提取并打印 value 值 if match: csrftoken_value = match.group(1) return csrftoken_value else: return "未找到 csrftoken" class HASH: #对字符串仅更新SHA256散列 def hash_password(password): """对密码进行SHA256散列""" return hashlib.sha256(password.encode('utf-8')).hexdigest()
2)修改TestEbusiness.py为Test_Register.py
代码语言:javascript
复制
… from Util import ClassDB from Util import CSRF from Util import HASH class TestUserRegistration(unittest.TestCase): # 注册接口的URL def setUp(self): self.REGISTER_URL = "http://127.0.0.1:8080/CharGPTEbusiness/jsp/register.jsp" self.session = requests.Session() response = self.session.get(self.REGISTER_URL) self.csrf = CSRF.get_csrf(response.text) self.token={"csrftoken":self.csrf} def tearDown(self): self.db = ClassDB() self.db.init_db() … 3) 修改Test_register_GUI.py … from Util import ClassDB import time REGISTER_URL = 'http://127.0.0.1:8080/CharGPTEbusiness/jsp/register.jsp' # 测试类 class TestUserRegistration: def teardown_class(self): self.db = ClassDB() self.db.init_db() … 4)建立Test_Login.py import requests import unittest from Util import ClassDB from Util import CSRF from Util import HASH # 基础URL BASE_URL = "http://127.0.0.1:8080/CharGPTEbusiness/jsp/login.jsp" # 替换为实际的登录API URL WELCOME_URL = "http://127.0.0.1:8080/CharGPTEbusiness/jsp//welcome.jsp" # 替换为实际的受保护页面URL class TestLoginAPI(unittest.TestCase): def setUp(self): self.session = requests.Session() response = self.session.get(BASE_URL) self.csrf = CSRF.get_csrf(response.text) self.token={"csrftoken":self.csrf} self.db = ClassDB() self.db.init_login() def tearDown(self): self.db.init_db() def test_valid_login(self): """TC-001:验证有效用户名和密码登录""" self.token['username'] = "validUser" response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "validUser", 'password': HASH.hash_password("ValidPassword123!") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("系统欢迎您", response.text) def test_invalid_username(self): """TC-002:验证无效用户名登录""" self.token['username'] = "invalidUser" response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "invalidUser", 'password': HASH.hash_password("ValidPassword123!") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("用户名或密码错误", response.text) def test_invalid_password(self): """TC-003,验证无效密码登录""" self.token['username'] = "validUser" response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "validUser", 'password': HASH.hash_password("wrongPassword") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("用户名或密码错误", response.text) def test_empty_username(self): """TC-004,验证空用户名登录""" self.token['username'] = "" response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "", 'password':HASH. hash_password("validPassword") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn(" ", response.text) def test_empty_password(self): """TC-005,验证空密码登录""" self.token['username'] = "validUser" response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "validUser", 'password': HASH.hash_password("") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("用户名或密码错误", response.text) def test_username_max_length(self): """TC-008,验证用户名最大长度""" self.token['username'] = "validUser12345678900" self.db.login_for_name("validUser12345678900") response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "validUser12345678900", 'password': HASH.hash_password("ValidPassword123!") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("系统欢迎您", response.text) def test_username_min_length(self): """TC-009,验证用户名最小长度""" self.token['username'] = "user1" self.db.login_for_name("user1") response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "user1", 'password':HASH.hash_password("ValidPassword123!") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("欢迎", response.text) self.assertIn("登录", response.text) self.assertIn("系统", response.text) def test_password_max_length(self): """TC-010,验证密码最大长度""" self.token['username'] = "validUser" self.db.login_for_password("ValidPassword1234567890123456!") response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "validUser", 'password': HASH.hash_password("ValidPassword1234567890123456!") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("系统欢迎您", response.text) def test_password_min_length(self): """TC-011,验证密码最小长度""" self.token['username'] = "validUser" self.db.login_for_password("P@ss1") response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "validUser", 'password': HASH.hash_password("P@ss1") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("系统欢迎您", response.text) def test_xss_injection(self): """TC-012,验证XSS注入""" self.token['username'] = " <> alert('XSS') " response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': " <> alert('XSS1') ", 'password': HASH.hash_password("ValidPassword123!") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("账号必须是5-20位字母或数字", response.text) def test_csrf_protection(self): """TC-013,验证CSRF保护""" # 假设CSRF令牌是必需的,这里我们不提供CSRF令牌 self.token['username'] = "validUser" response = requests.post(BASE_URL, data={ 'username': "validUser", 'password': HASH.hash_password("ValidPassword123!") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn(" ", response.text) def test_sql_injection(self): """TC-014,验证SQL注入""" self.token['username'] = "admin' --" response = requests.post(BASE_URL, data={ 'csrftoken':self.csrf, 'username': "admin' --", 'password': HASH.hash_password("ValidPassword123!") },cookies=self.token) self.assertEqual(response.status_code, 200) self.assertIn("账号必须是5-20位字母或数字", response.text) if __name__ == "__main__": unittest.main() 10.3 生成登录GUI测试用例 10.3.1 申请生成登录GUI测试用例 对下面用例书写基于playwright+pytest的测试脚本。
前端代码
代码语言:javascript
复制
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="../css/index.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/core.js"></script> <script src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/sha256.js"></script> <title>登录页面</title> <script src="../js/index.js" type="text/javascript"></script> </head> <body> <div class="container"> <h2>登录</h2> <form id="loginForm" name="loginForm" method="POST" action="login.jsp" onsubmit="return validateLoginForm();"> <input type="hidden" id="csrftoken" name="csrftoken" value="yDhOJU4vOCv6qSENtpba8xaURQlQlpGQ9W4hJekAt45dLi9ByMEs2DOzaLwtjeo2P4b1pV0crpDqxQo1F3w23blijWE1OBsj99ke"> <div> <label for="username">用户名:</label> <input type="text" id="username" name="username" placeholder="输入账号" required> <div id="usernameError" class="error"></div> </div> <div> <label for="password">密码:</label> <input type="password" id="password" name="password" placeholder="输入密码" required> <div id="passwordError" class="error"></div> </div> <button type="submit">登录</button> </form> <div id="loginError" class="error"> </div> </div> </body> </html>
对下面用例实现基于GUI的测试用例
TC-001 验证有效用户名和密码登录,用户名: validUser,登录成功,显示“登录XXXX系统”提示。
TC-002 验证无效用户名登录,用户名: invalidUser,显示“用户名或密码错误”。
TC-006 验证用户名长度边界,用户名: "a"(1个字符),显示“账号必须是5-20位字母或数字”。
TC-007 验证密码长度边界,密码: "123"(3个字符),显示“密码必须包含大小写字母、数字和特殊字符,长度在5-30之间”。
TC-015 验证未登录用户访问登录后地址,登录,然后登出,直接访问: "/welcome.jsp"重定向回登录页面。
假设存在一个账户,用户名:validUser,密码:ValidPassword123!。
10.3.2 生成登录GUI测试用例回复
下面是基于Playwright和pytest的测试脚本实现,涵盖了您提供的用例。请确保您已经安装了Playwright和pytest,并且已正确配置了测试环境。
首先,您需要在项目目录中创建一个新的Python文件,比如test_login.py,然后将以下代码粘贴到该文件中:
代码语言:javascript
复制
import pytest from playwright.sync_api import sync_playwright # 测试用例 @pytest.mark.parametrize("username, password, expected_message", [ ("validUser", "ValidPassword123!", "登录XXXX系统"), # TC-001 ("invalidUser", "ValidPassword123!", "用户名或密码错误"), # TC-002 ("a", "ValidPassword123!", "账号必须是5-20位字母或数字"), # TC-006 ("validUser", "123", "密码必须包含大小写字母、数字和特殊字符,长度在5-30之间"), # TC-007 ]) def test_login(username, password, expected_message): with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() page.goto("file://path/to/your/html/file.html") # 替换为您的HTML文件路径 # 填充用户名和密码 page.fill("#username", username) page.fill("#password", password) # 提交表单 page.click("button[type='submit']") # 等待页面加载并验证消息 page.wait_for_selector("#loginError, h2") # 等待登录错误或成功消息 if expected_message == "登录XXXX系统": assert page.locator("h2").inner_text() == expected_message else: assert page.locator("#loginError").inner_text() == expected_message browser.close() def test_access_protected_page_after_logout(): with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() # 登录 page.goto("file://path/to/your/html/file.html") # 替换为您的HTML文件路径 page.fill("#username", "validUser") page.fill("#password", "ValidPassword123!") page.click("button[type='submit']") # 退出登录 # 假设有一个退出登录的按钮,您需要根据实际情况进行调整 page.click("#logoutButton") # 替换为实际的注销按钮选择器 # 尝试访问受保护的页面 page.goto("file:///path/to/welcome.jsp") # 替换为欢迎页面的真实路径 # 验证重定向回登录页面 assert page.url == "file://path/to/your/html/file.html" # 替换为登录页面的真实路径 browser.close()
说明
测试用例: 使用@pytest.mark.parametrize装饰器来定义多个测试用例,涵盖有效和无效的用户名和密码。
浏览器操作: 使用Playwright的API来启动浏览器、打开页面、填写表单、提交表单并验证结果。
重定向测试: test_access_protected_page_after_logout函数用于测试未登录用户访问受保护页面的情况。
路径替换: 请确保将file://path/to/your/html/file.html和file:///path/to/welcome.jsp替换为您本地的实际文件路径。
运行测试
确保您已安装pytest和Playwright。您可以通过以下命令运行测试:
代码语言:javascript
复制
pytest test_login.py
请根据您的具体需求和环境进行调整。
10.3.3调整登录GUI测试程序
代码语言:javascript
复制
import pytest from playwright.sync_api import Page from Util import ClassDB import time LOGIN_URL = 'http://127.0.0.1:8080/CharGPTEbusiness/jsp/login.jsp' WELCOME_URL ='http://127.0.0.1:8080/CharGPTEbusiness/jsp/welcome.jsp' # 测试类 class TestUserLogin: def setup_class(self): self.db = ClassDB() self.db.init_login() def teardown_class(self): self.db.init_db() # 测试用例 @pytest.mark.parametrize("username, password, expected_message", [ ("validUser", "ValidPassword123!", "系统欢迎您"), # TC-001 ("invalidUser", "ValidPassword123!", "用户名或密码错误"), # TC-002 ("a", "ValidPassword123!", "账号必须是5-20位的字母或数字"), # TC-006 ("validUser", "123", "密码必须包含大小写字母、数字和特殊字符,长度在5-30之间"), # TC-007 ]) def test_login(self,page: Page,username, password, expected_message): page.goto(LOGIN_URL) page.reload() # 填充用户名和密码 page.fill("#username", username) page.fill("#password", password) page.click("button[type='submit']") # 等待页面加载并验证消息 if expected_message == "系统欢迎您": page.wait_for_selector("h1") # 等待成功消息 else: page.wait_for_selector("h2") # 等待登录错误 if username == "validUser": if password != "123": assert page.locator("h1").inner_text() == expected_message else: assert expected_message in page.locator("#passwordError").inner_text() elif username == "invalidUser": assert expected_message in page.locator("#loginError").inner_text() elif username == "a": assert expected_message in page.locator("#usernameError").inner_text() else: assert 0==1 def test_access_protected_page_after_logout(self,page: Page): # 登录 page.goto(LOGIN_URL) page.reload() page.fill("#username", "validUser") page.fill("#password", "ValidPassword123!") page.click("button[type='submit']") page.wait_for_selector("h1") # 等待成功消息 page.click("body > a") # 替换为实际的注销按钮选择器 # 尝试访问受保护的页面 page.goto(WELCOME_URL) # 替换为欢迎页面的真实路径 # 验证重定向回登录页面 assert page.url == LOGIN_URL # 替换为登录页面的真实路径 if __name__ == '__main__': pytest.main(["-sv", "Test_login_GUI.py"])
在这里注意
代码语言:javascript
复制
由于expected_messagez在页面中不同的地方出现,所以调整代码: if username == "validUser": if password != "123": assert page.locator("h1").inner_text() == expected_message else: assert expected_message in page.locator("#passwordError").inner_text() elif username == "invalidUser": assert expected_message in page.locator("#loginError").inner_text() elif username == "a": assert expected_message in page.locator("#usernameError").inner_text() else: assert 0==1
另外在运行过程中发现:
代码语言:javascript
复制
page.fill("#username", "…") page.fill("#password", "…") page.click("button[type='submit']")
经常等待不到,后来通过playwright的录制功能,换了
代码语言:javascript
复制
page.get_by_placeholder("输入账号").fill("validUser") page.get_by_placeholder("输入密码").fill("ValidPassword123!") page.get_by_role("button", name="登录").click()
就没有问题了。
注意:在使用ChatGPT辅助开发代码的时候,注意结合其他工具一起使用 |
另外在运行过程中发现每次密码没有执行散列就传输了,后来发现前端代码
代码语言:javascript
复制
< src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/sha256.js">
由于网速很慢,https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/sha256.js无法加载到。把core.js、crypto-js.min.jsh和sha256.js放在项目js目录下。register.jsp和login.js改为:
代码语言:javascript
复制
< src="../js/crypto-js.min.js"> < src="../js/core.js"> < src="../js/sha256.js">
10.3.4调整注册GUI测试程序
根据登录GUI测试程序调整注册GUI测试。使用pytest.mark.parametrizec参数模式。
注意:ChatGPT每次给出的格式不一致,需要根据经验使用最好的程序 |
代码语言:javascript
复制
import pytest from playwright.sync_api import Page from Util import ClassDB import time REGISTER_URL = 'http://127.0.0.1:8080/CharGPTEbusiness/jsp/register.jsp' # 测试类 class TestUserRegistration: def teardown(self): self.db = ClassDB() self.db.init_db() # 测试用例 @pytest.mark.parametrize("username, password, repassword, phone, email, expected_message", [ ("validUser123", "ValidPass123!", "ValidPass123!","13800138000","test@example.com","登录"), #GTC1-账号有效性测试 ("testUser", "Aa1@", "Aa1@","13800138000","test@example.com","密码必须包含大小写字母、数字和特殊字符,长度在5-30之间"), #GTC2 - 密码长度不足测试 ("testUser", "iLongpassword12@Longpassword12@", "iLongpassword12@Longpassword12@","13800138000","test@example.com","密码必须包含大小写字母、数字和特殊字符,长度在5-30之间"), #GTC3 - 密码长度超出测试 ("testUser", "ValidPass123!", "validPass123!","13800138000","test@example.com","密码确认不一致"), #GTC4 - 输入密码与确认密码确保不一致性 ("testUser", "ValidPass123!", "ValidPass123!","12345","test@example.com","请输入有效的中国手机号"), ##GTC5 - 手机号格式错误测试 ]) def test_Login(self,page: Page,username, password, repassword, phone, email, expected_message): page.goto(REGISTER_URL) page.reload() page.fill('input[name="username"]', username) page.fill('input[name="password"]', password) page.fill('input[name="confirmPassword"]', repassword) page.fill('input[name="phone"]', phone) page.fill('input[name="email"]', email) page.click('button[type="submit"]') # 检查注册是否成功(这里需要根据实际页面反馈调整) if expected_message == "登录": assert page.get_by_role("heading", name="登录") else: assert page.locator('text='+expected_message).is_visible() # 测试用例 @pytest.mark.parametrize("username, password, repassword, phone, email, username_1,phone_1,email_1,expected_message", [ ("duplicateUser", "ValidPass123!", "ValidPass123!","13800138000","duplicate@example.com","duplicateUser","13800138001","duplicate2@example.com","注册用户的用户名必须唯一"), #GTC6 – 一个用户重复注册两次。 ("duplicateUser3", "ValidPass123!", "ValidPass123!","13800138003","duplicate1@example.com","duplicateUser4","13800138003","duplicate1@example.com","注册用户的手机必须唯一"), #GTC7 – – 不同用户注册,手机号重复 ("duplicateUser1", "ValidPass123!", "ValidPass123!","13800138004","duplicate3@example.com","duplicateUser4","13800138005","duplicate3@example.com","注册用户的邮箱必须唯一"), #GTC8 – 不同用户注册,邮件重复 ]) def test_duplicate(self,page: Page,username, password, repassword, phone, email, username_1,phone_1,email_1,expected_message): page.goto(REGISTER_URL) page.reload() # 第一次注册 page.fill('input[name="username"]', username) page.fill('input[name="password"]', password) page.fill('input[name="confirmPassword"]', repassword) page.fill('input[name="phone"]', phone) page.fill('input[name="email"]', email) page.click('button[type="submit"]') # 检查注册成功 assert page.get_by_role("heading", name="登录") # 第二次注册相同用户 page.goto(REGISTER_URL) page.reload() page.fill('input[name="username"]', username_1) page.fill('input[name="password"]', password) page.fill('input[name="confirmPassword"]', repassword) page.fill('input[name="phone"]', phone_1) page.fill('input[name="email"]', email_1) page.click('button[type="submit"]') # 检查错误信息 print(expected_message) assert page.locator('text='+expected_message).is_visible() if __name__ == '__main__': pytest.main(["-sv", "Test_register_GUI.py"])
10.4 总结
共有以下测试用例,其中API测试用例12个,分别如下:
TC-001 验证有效用户名和密码登录
TC-002 验证无效用户名登录
TC-003 验证无效密码登录
TC-004 验证空用户名登录
TC-005 验证空密码登录
TC-008 验证用户名最大长度
TC-009 验证用户名最小长度
TC-010 验证密码最大长度
TC-011 验证密码最小长度
TC-012 验证XSS注入
TC-013 验证CSRF保护
TC-014 验证SQL注入
GUI测试用例5个,分别如下:
TC-001 验证有效用户名和密码登录
TC-002 验证无效用户名登录
TC-006 验证用户名长度边界
TC-007 验证密码长度边界
TC-015 验证未登录用户访问登录后地址
没有手工测试用例。