web测试用例
- 放在excel中,用例中应该包含:ID、用例名称、功能模块、前置条件、执行步骤和预期结果
- 作自动化测试的时候,首要考虑的是用例的独立性,任何情况下都是可以直接执行的,不依赖与前后测试用例的执行或者测试环境的切换,因此为了维护用管理的独立性,需要每一条用例都打开一次浏览器,执行用例后直接关闭
- 如果在保证测试用例互不影响的情况下,可以打开一次浏览器,执行多条用例来节约时间
- web自动化测试,在写代码之前现将用例设计好并写出来,明确自己会写什么样的用例,需要用到什么样的功能,在封装页面的时候,第一阶段只封装我们需要用到的属性或页面功能,其他用不到的可以不编写。
用例编写常识
- 不是所有的手工测试用例都要转换为自动化测试用例
- 考虑到脚本的开发成本,不要选择流程太负责的用例,如果有必要,可以考虑流程拆分成多个用例来实现脚本
- 选择的用例最好可以构建成场景,例如一个功能模块,分多个测试用例,多个测试用例使用同一个场景
- 选择的用例开一带有目的性,例如:这比分是用例的冒烟测试,那部分是用例的回归测试等等,当然,会存在重叠的关系,如果当前用例能不能满足需求,那么唯有修改用例来适应脚本和需求
- 选取的用例可以是你认为重读执行,很繁琐的部分,例如:字段验证、提示信息验证,这部分适用于回归测试
- 选取的用例可以是主流程,这部分适用于冒烟测试
- 自动化测试也可以用来配置检查、数据库检查,这一部分可能超过手工测试,算是拓展的一部分,项目负责人可以选择的增加
- 平时在手工测试时,如果需要构建一些复杂的数据或者重复简单的机械的动作,告诉自动化脚本,让他来帮你,或许你的效率会因此提高
用例编写原则
- 一个用例为一个场景,从用户登录系统到最终退出关闭浏览器
- 一个用例只验证一个功能点,不要试图在用户登录系统后将所有的功能都验证一遍
- 尽量少的编写逆向逻辑用例,一方面因为逆向逻辑用例很多(例如手机号输入错误就有好几种情况);另一方面,自动化测试脚本本身就比较脆弱,对于复杂的逆向逻辑用例的实现比较麻烦并且容易出错
- 用例和用例之间,尽可能的避免依赖
- 一条用例完成之后,需要对测试场景进行还原,避免影响其他测试用例的执行
用例前置条件
- 要将编写的用例列出(什么形式都好)—— 包含:前置、步骤和断言
- 需要明确涉及那些页面
- 前置条件利用各种手段准备,获取数据的时候可以使用接口或去查数据库,建议修改数据的时候通过接口修改。接口查询也是最好的方式
- 注意:用例的步骤和断言必须要走页面,不能走接口
- 用例的前置条件,不能调用测试用例,建议调用页面行为
- 公共数据中不仅仅可以放url,也可以将公用的数据放在里面
代码示例——以腾讯课堂为例
页面xpath
from selenium.webdriver.common.by import By
class LoginXpath:
button_login = (By.XPATH,'//div[@id="js-mod-entry-index"]//a')
iframe_xpath = (By.XPATH, '//div[@class="login-qq-iframe-wrap"]//iframe')
user_pwd_login = (By.ID,"switcher_plogin")
user_text = (By.ID, 'u')
pwd_text = (By.ID, 'p')
login_button = (By.ID, 'login_button')
text_error_mes =(By.ID, 'err_m')
user_mes = (By.XPATH,'//a[text()="退出"]')
from selenium.webdriver.common.by import By
class UserPage:
class_search_text=(By.XPATH,'//*[@id="js_keyword"]')
class_search_button = (By.XPATH,'//*[@id="js_search"]')
search_class = (By.XPATH,'//dl[@class="sort-nav-order sort-nav-order-my sort-nav-top js-sort-nav-top"]//a[@class="cur-top"]')
search_order_by = (By.XPATH,'//dd[@id="auto-test-5"]//a')
class_click = (By.XPATH,'//li[@class="course-card-item--v3 js-course-card-item "][1]')
from selenium.webdriver.common.by import By
class ClassDetailsPage:
buy_button = (By.XPATH,'//div[@id="js_btn_bar"]//*[@class="general-btn-txt institution-btn-txt"]')
pay_button = (By.XPATH,'//*[@class="im-btn purchase-bottom-btn btn-default btn-m"]')
commodity_order = (By.XPATH,'//*[@class="ep-order-tit"]//dt')
页面操作类
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from web_unittest.test_PO.class_test_datas.class_xpath_login import LoginXpath as LX
class Login:
def __init__(self,driver):
self.driver = driver
def click_login_button(self):
WebDriverWait(self.driver,40).until(
EC.visibility_of_element_located(LX.button_login))
self.driver.find_element(*LX.button_login).click()
def ifram_swith_and_click_user_pwd(self):
WebDriverWait(self.driver,40).until(
EC.frame_to_be_available_and_switch_to_it(LX.iframe_xpath))
self.driver.find_element(*LX.user_pwd_login).click()
def send_login_data(self,user,pwd):
WebDriverWait(self.driver,40).until(
EC.visibility_of_element_located(LX.user_text))
self.driver.find_element(*LX.user_text).send_keys(user)
self.driver.find_element(*LX.pwd_text).send_keys(pwd)
self.driver.find_element(*LX.login_button).click()
def error_msg(self):
WebDriverWait(self.driver,40).until(
EC.visibility_of_element_located(LX.text_error_mes))
return self.driver.find_element(*LX.text_error_mes).text
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from web_unittest.test_PO.class_test_datas.class_Xpath_user import UserPage as US
from web_unittest.test_PO.class_test_datas.class_class_details import ClassDetailsPage as CL
from web_unittest.test_PO.class_test_datas.class_xpath_login import LoginXpath as LX
class UserPage:
def __init__(self,driver):
self.dirver = driver
def isExit_name(self):
try:
WebDriverWait(self.dirver, 40).until(
EC.visibility_of_element_located(LX.user_mes))
return True
except:
return False
def search_class(self,mes):
time.sleep(5)
self.dirver.find_element(*US.class_search_text).send_keys(mes)
self.dirver.find_element(*US.class_search_button).click()
def isExitClass(self):
WebDriverWait(self.dirver, 40).until(
EC.visibility_of_element_located(US.search_class))
self.dirver.find_element(*US.search_class).click()
element= self.dirver.find_element(*US.search_order_by)
self.dirver.execute_script("arguments[0] .scrollIntoView();", element)
element.click()
def switch_alart(self):
handles_list = self.dirver.window_handles
self.dirver.find_element(*US.class_click).click()
WebDriverWait(self.dirver, 40).until(EC.new_window_is_opened(handles_list))
handles_list_new = self.dirver.window_handles
self.dirver.switch_to.window(handles_list_new[-1])
def click_buy(self):
WebDriverWait(self.dirver, 40).until(
EC.visibility_of_element_located(CL.buy_button))
self.dirver.find_element(*CL.buy_button).click()
def click_pay(self):
WebDriverWait(self.dirver, 40).until(
EC.visibility_of_element_located(CL.pay_button))
self.dirver.find_element(*CL.pay_button).click()
def isExit(self):
try:
WebDriverWait(self.dirver, 40).until(
EC.visibility_of_element_located(CL.commodity_order))
return True
except:
return False
数据准备
login_url = 'https://ke.qq.com/'
login_success_datas = {"user":"XXX","pwd":"XXX"}
login_fail_datas = [
{"user":"XXX","pwd":"","excpet":"你还没有输入密码!"} ,
{"user":"XXX","pwd":"XXX","excpet":"你输入的帐号或密码不正确,请重新输入。"},
]
测试用例
- setUpClass和setUp在unittest中可以同时存在,运行的时候,先运行setUpClass
- setUpClass在用例中只调用一次,setUp每条用例都会执行
- 同理还有tearDown和tearDownClass
@classmethod
def setUpClass(cls):
pass
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.get(CO.login_url)
user = Lo.login_success_datas.get("user")
pwd = Lo.login_success_datas.get("pwd")
Login(driver=self.driver).click_login_button()
Login(driver=self.driver).ifram_swith_and_click_user_pwd()
Login(driver=self.driver).send_login_data(user,pwd)
def test_buy_class(self):
UserPage(self.driver).search_class("柠檬班")
UserPage(self.driver).isExitClass()
UserPage(self.driver).switch_alart()
UserPage(self.driver).click_buy()
UserPage(self.driver).click_pay()
self.assertTrue(UserPage(self.driver).isExit())
def tearDown(self):
self.driver.quit()
@classmethod
def tearDownClass(cls):
pass
import unittest
from selenium import webdriver
from web_unittest.test_PO.page_object.class_login_page import Login
from web_unittest.test_PO.page_object.class_user_page import UserPage
from web_unittest.test_PO.class_test_datas import test_common_data as CO
from web_unittest.test_PO.class_test_datas import class_login_data as Lo
from ddt import ddt,data
@ddt
class TestLogin(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.get(CO.login_url)
def test_login_success(self):
user = Lo.login_success_datas.get("user")
pwd = Lo.login_success_datas.get("pwd")
Login(driver=self.driver).click_login_button()
Login(driver=self.driver).ifram_swith_and_click_user_pwd()
Login(driver=self.driver).send_login_data(user,pwd)
self.assertTrue(UserPage(driver=self.driver).isExit_name())
@data(*Lo.login_fail_datas)
def test_login_no_pwd(self,datas):
user = datas.get("user")
pwd = datas.get("pwd")
excpet = datas.get("excpet")
Login(driver=self.driver).click_login_button()
Login(driver=self.driver).ifram_swith_and_click_user_pwd()
Login(driver=self.driver).send_login_data(user,pwd)
actual = Login(driver=self.driver).error_msg()
self.assertEqual(excpet,actual)
def tearDown(self):
self.driver.quit()