答疑
測試
概念:驗證軟件是否滿足用戶需求
測試和開發的區別
調試和測試
-
目的
測試:檢查軟件是否實現了應該實現的功能;
調試:是程序員檢查軟件是否實現了該代碼應該實現的功能。 -
角色
開發:程序員
測試:測試人員和開發人員 -
階段
開發:只在開發階段調試
測試:在軟件開發的整個生命周期
技術
測試:技術要求廣,但是深度低一些。要求使用各種工具和懂一些語言
開發:技術要求專一,深度高
為什么選擇軟件測試
- 興趣
- 技能
- 抗壓能力
- 責任感
為什么不做開發,而做測試
學習了開發知識 ==> 了解到軟件測試 ==> 感興趣 ==> 學習開發更好地進行測試
概念
需求
概念:滿足用戶需求或正式文檔所需的權限和技能
測試人員在需求階段就介入了測試
用戶需求:用戶想干什么,吃紅燒肉
軟件需求:做紅燒肉需要干什么?買肉、買佐料等
BUG
概念:當且僅當規格說明存在且合理的情況下,軟件的功能和需求規格說明不符合,說明是軟件錯誤;
當軟件規格說明不存在,用戶需求合理,軟件功能和需求規格不相符,說明軟件錯誤。
也就是說,不管規格說明存在與否,只要用戶需求合理,但是軟件功能和需求規格說明不符合,則是 bug
測試用例
概念:向測試系統發起的一組集合;包含:測試環境、測試步驟、測試數據、預期結果、標題、測試功能模塊、優先級、重要性等。
開發模型
瀑布模型

螺旋模型

迭代、增量模型

敏捷模型
角色:產品經理(PO)、項目經理(SM)、研發團隊(ST)
產品發布會議 ==> 迭代計劃會議 ==> 開發期間每日站會 ==> 演示會議 ==> 回顧會議
軟件測試模型
測試人員什么時候開始介入測試的?
- W 模型中,在需求分析時介入;
缺點:串行執行,不支持敏捷開發;
V 模型中,在編碼后介入。
缺點:無法在需求階段介入
基礎
軟件測試流程(軟件測試生命周期)
需求分析 ==> 測試計劃 ==> 測試設計 / 開發 ==> 測試執行 ==> 測試報告
如何描述一個 BUG
測試版本(系統版本) + 測試環境(瀏覽器版本等) + 測試步驟 + 測試數據 + 預期結果 + 實際結果 + 附件(錯誤截圖、錯誤日志)
BUG 級別
崩潰
嚴重
一般
建議
系統新功能上線,發現用戶在使用某一個功能時崩潰了,且無法修復,這個時候測試人員如何處理?
- 回退版本(系統穩定的版本)
- 抓緊實現修復問題
BUG 的生命周期

開發人員修復一個 BUG 后,測試的時候任然發現 BUG 存在,可能的原因
- 開發檢查,修復代碼后是否提交新代碼;
- 測試人員沒有重新提取測試環境的代碼;
- 確實是開發人員沒有修改成功。
如何處理測試人員和開發人員因為 BUG 產生沖突怎么辦?
- 檢查自身 BUG 描述是否清楚,BUG 檢查是否正確;
- 站在用戶的角度去說服開發人員;
- BUG 的定級有理有據,不要夸大其詞;
- 測試人員不斷提高自己的水平,能夠發現 BUG 及其產生的原因,還有解決方案;
- 開三方會議(產品經理、開發人員、測試人員)一起討論 BUG 解決方案。
用例
設計測試用例依據
根據需求來設計測試用例
分析需求、細化需求、從需求中提取功能點 / 測試點,然后再用設計測試的具體方法設計測試用例;
黑盒測試設計測用例方法
等價類、邊界值、因果圖、場景設計法、錯誤猜測法、正交法
測試用例設計方法
等價類
概念:把輸入(特殊情況才考慮輸出)劃分成若干個等價類,從每一個等價類當中選取一個測試用例進行測試,如果這個測試用例通過,就說明這個測試用例代表的等價類測試通過。
使用情況:測試用例太多無法窮舉
有效等價類:對該功能輸入有意義的輸入(輸入合法的用戶名)
無效等價類:對該功能輸入無意義的輸入(輸入不合法的用戶名)
邊界值
概念:針對輸入的邊界進行測試用例的設計
因果圖
使用情況:輸入有多個條件,并且輸入不同組合對應著不同輸入
邏輯關系:與 或 非 恒等
使用步驟:分析可能的輸入和輸出 ==> 找出輸入與輸出之間的優惠 ==> 畫出因果圖 ==> 將因果圖畫出判定表 ==> 根據判定表寫測試用例
-
分析可能的輸入輸出
輸入:訂單提交、金額大于 300、有紅包
輸出:有優惠、無優惠 -
找出輸入與輸出之間的優惠

-
畫因果圖

-
畫判定表:有 3 個輸入,2 個輸出,對應的列數 2^3 = 8

場景法
概念:把系統中一個一個孤立的功能點按照一定的邏輯組合起來,形成一個場景 / 業務,針對場景進行測試
首先確定場景中的每一個功能點,確定功能點可能的輸入和不同的輸出
錯誤猜測法
概念:根據測試人員的直覺、經驗、知識去判斷系統某一模塊的問題,有針對性的設計測試用例
正交法
概念:研究多因素(不同的輸入)多水平(不同輸入不同的取值)的一種測試用例設計方法,根據正交性,選出最優的輸入組合進行試驗,分析試驗結果,用結果衡量整體試驗的結果
TCP 和 UDP 協議怎么測試?
分別分析 TCP 與 UDP 的作用以及特點
TCP
作用:傳輸數據
特點:可靠(是否收到 ACK),三次握手(根據三次握手每次發送的信號不同進行測試),數據流,四次揮手等UDP
作用:傳輸數據
特點:數據報、不可靠、速度快。
進階
按照開發階段劃分
單元測試
分類:Junit 單元測試框架(白盒)、unittest 單元測試框架(黑盒)
依據:詳細設計文檔
集成測試
概念:集成測試也稱聯合測試(聯調)、組裝測試,將程序模塊采用適當的集成策略組裝起來,對系統的接口及集成后的功能進行正確性檢測的測試工作。集成主要目的是檢查軟件單位之間的接口是否正確。
測試方法:白盒測試
冒煙測試
冒煙測試的對象是每一個新編譯的需要正式測試的軟件版本,目的是確認軟件基本功能正常,可以進行后續的正式測試工作,也就是系統測試。冒煙測試的執行者是版本編譯人員。
系統測試
將軟件系統看成是一個系統的測試。包括對功能、性能以及軟件所運行的軟硬件環境進行測試。時間大部分在系統測試執行階段,包括回歸測試和冒煙測試。
測試方法:黑盒測試
回歸測試
概念:查看新引入的代碼對舊的功能是否有影響
驗收測試
驗收測試是部署軟件之前的最后一個測試操作。它是技術測試的最后一個階段,也稱為交付測試。驗收測試的目的是確保軟件準備就緒,按照項目合同、任務書、雙方約定的驗收依據文檔,向軟件購買都展示該軟件系統滿足原始
需求。
按實施組織劃分
α測試
非測試、非開發人員進行測試
β測試
真實用戶不分時間地點進行測試(內測)
按照是否手工劃分
手工測試
手工測試就是由人去一個一個的輸入用例,然后觀察結果,和機器測試相對應,屬于比較原始但是必須的一個。
優點:自動化無法替代探索性測試、發散思維結果的測試。
缺點:執行效率慢,量大易錯。
自動化測試
編寫自動化腳本,把設計的測試用例進行測試
自動化測試無法代替手工測試
是否運行代碼
靜態測試
不運行代碼,分析代碼進行測試
動態測試
運行代碼,檢查預期結果與實際結果的異同分析差異、運行效率、正確性等
按是否查看代碼劃分
黑盒測試(unittest)
把軟件看成一個黑色盒子,不關心軟件內部代碼的邏輯結構實現,只關心輸入輸出
白盒測試(Junit)
測試程序的內部邏輯、結構的實現,是否實現了相應的功能
測試方法:語句覆蓋、邏輯覆蓋(判定覆蓋 / 條件覆蓋 / 判定組合 / 條件組合 / 判定和條件組合) 、路徑覆蓋(if / else / try / catch)、循環覆蓋(for / while)
按照測試對象劃分
業務測試
概念:是測試人員把系統各個模塊串接起來運行、模擬真實用戶實際的工作流程,滿足用戶需求定義的功能來進行測試的
過程。
界面測試
- 布局排盤
- 字體大小、粗細等
- 圖片是否清晰
- 頁面的控件(按鈕、滾動條、CheckBox 等)
容錯性測試
概念:當系統由于外界原因發生異常時,能自我處理,不把異常直接展現給用戶,給用戶一個友好的提示
易用性測試
易用性(Useability)是交互的適應性、功能性和有效性的集中體現。易用性屬于人體工程學的范疇,人體工程學(ergonomics)是一門將日常使用的東西設計為易于使用和實用性強的學科
兼容性
兼容性主要是指軟件之間能否很好的運做,會不會有影響、軟件和硬件之間能否發揮很好的效率工作,會不會影響導致系統的崩潰。
文檔測試
在實際的測試中,最常見的是用戶文件的測試,例如:手冊說明書等。也會有一些公司對需求文檔進行測試,來保證需求文檔的質量。
性能測試
檢查系統是否滿足需求規格說明書中規定的性能。
安全性測試
安全測試是一個相對獨立的領域,需要更多的專業知識。例如web的安全測試,需要熟悉各種網絡協議
TCP\HTTP,防火墻,CDN,熟悉各種操作系統的漏洞,熟悉路由器等。從軟件來說,熟悉各種攻擊手段,例如 SQL 注入、Xss 等。
內存泄漏測試
用戶在分配了內存空間,沒有回收,導致占用的內存越來越多。
自動化測試(selenium)
webdriver 基本使用
定位元素的方式
# 用 id 定位
輸入框 id = kw 發送 張嘉文 到輸入框
driver.find_element_by_id("kw").send_keys("張嘉文")
# 百度一下(提交搜索) click 點擊
driver.find_element_by_id("su").click()
# 用 name 定位
driver.find_element_by_name("wd").send_keys("張嘉文")
driver.find_element_by_id("su").click()
# class name 定位
driver.find_element_by_class_name("s_ipt").send_keys("張嘉文")
driver.find_element_by_class_name("bg s_btn").click()
# link text 定位
driver.find_element_by_link_text("貼吧").click()
# partial 定位
driver.find_element_by_partial_link_text("吧").click()
# tag name 定位
driver.find_element_by_tag_name("")
# xpath 定位
driver.find_element_by_xpath("http://*[@id='kw']").send_keys("張嘉文")
driver.find_element_by_xpath("http://*[@id='su']").click()
# css selector
driver.find_element_by_css_selector("#kw").send_keys("張嘉文")
driver.find_element_by_css_selector("#su").click()
等待
time.sleep(3)
driver.implicitly_wait(3)
異同
同:與 time.wait(10) 相同的是, 兩者如果等待 10s 都沒有找到下一個需要的元素, 那么就會拋出異常
異:time.sleep() 是固定等待;而 driver.implicotly_wait() 則是等到找到就繼續執行,而不是死等
得到瀏覽器標題和 URL
# 獲得標題
driver.title
# 獲得 URL
driver.current_url
瀏覽器窗口大小
# 設置瀏覽器窗口
driver.set_window_size(600,1000)
# 瀏覽器最大化
driver.maximize_window()
前進后退
# 前進
driver.forward()
# 后退
driver.back()
鍵盤
# 需要的包
from selenium.webdriver.common.keys import Keys
# 用法
driver.find_element_by_name("username").send_keys(Keys.CONTROL,'a')
driver.find_element_by_name("username").send_keys(Keys.CONTROL,'c')
driver.find_element_by_name("password").send_keys(Keys.ENTER)
鼠標
# 需要的包
from selenium.webdriver.common.action_chains import ActionChains
# 右擊
name = driver.find_element_by_id("su")
ActionChains(driver).context_click(name).perform()
# 雙擊
ActionChains(driver).double_click(name1).perform()
多選 (CheckBox)
for input in inputs:
if input.get_attribute('type') == 'checkbox':
input.click()
下拉框
# 通過 css selector 定位
driver.find_element_by_css_selector("#ShippingMethod > option:nth-child(5)").click()
# 數組下標
options[2].click()
彈出框
driver.switch_to.alert.accept()
上傳文件
driver.find_element_by_tag_name("input").send_keys("F:\\圖片\\0.jpg")
層級框架

從默認框架到 f2,需要先到 f1;
從 f2 到默認框架,也需要先到 f1;
unittest 框架
測試固件
from selenium import webdriver
import unittest
import time
import os
# unittest.TestCase 的作用:Unit 這個類繼承了 unittest.TestCase
class Unit(unittest.TestCase):
def setUp(self):
print("run setUp")
self.driver = webdriver.Chrome()
self.url = "https://www.baidu.com/"
self.driver.maximize_window()
def tearDown(self):
print("run tearDown")
self.driver.quit()
if __name__=="__main__":
unittest.main()
測試套件
from Test import unitDemo
from Test import unitDemo1
import unittest
def createsuite():
# addTest 每次把一個測試腳本的一個測試用例加載到測試套件
suite = unittest.TestSuite()
suite.addTest(unitDemo.Unit("test_Abaidu"))
suite.addTest(unitDemo.Unit("test_abaidu"))
suite.addTest(unitDemo1.Unit("test_cbaidu"))
suite.addTest(unitDemo1.Unit("test_Dbaidu"))
def createsuite1():
# 把一個測試腳本中的所有測試用例加載進入套件
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(unitDemo.Unit))
suite.addTest(unittest.makeSuite(unitDemo1.Unit))
return suite
def createsuite2():
# TestLoader
# 把一個測試腳本中的所有測試用例加載進入套件
suite1 = unittest.TestLoader().loadTestsFromTestCase(unitDemo.Unit)
suite2 = unittest.TestLoader().loadTestsFromTestCase(unitDemo1.Unit)
suite = unittest.TestSuite([suite1, suite2])
return suite
def createsutie3():
# 把一個文件夾下所有以某種形式命名的測試腳本全部加入到測試套件
discover = unittest.defaultTestLoader.discover("../Test", pattern="unitDemo*.py",top_level_dir=None)
return discover
if __name__=="__main__":
suite = createsuite1()
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
忽略測試用例執行
@unittest.skip("skipping")
# 注解:忽略測試用例執行
def test_abaidu(self):
driver = self.driver
url = "https://www.baidu.com/"
self.driver.get(url)
driver.find_element_by_id("kw").send_keys("豬頭")
driver.find_element_by_id("su").click()
time.sleep(3)
title = driver.title
try:
self.assertEqual("豬頭_百度一下", title, msg="不相等")
except:
self.saveScreenShot(self,driver,"豬頭.png")
time.sleep(3)
斷言
作用:判斷預期結果與實際結果是否一致
# 斷言
def test_abaidu(self):
driver = self.driver
url = "https://www.baidu.com/"
self.driver.get(url)
driver.find_element_by_id("kw").send_keys("豬頭")
driver.find_element_by_id("su").click()
time.sleep(3)
title = driver.title
try:
self.assertEqual("豬頭_百度一下", title, msg="不相等")
except:
self.saveScreenShot(self,driver,"豬頭.png")
time.sleep(3)
截圖
# 運行順序 0-9 A-Z a-z
# 截圖
def test_Abaidu(self):
driver = self.driver
url = self.url
driver.get(url)
driver.find_element_by_id("kw").send_keys("是你")
driver.find_element_by_id("su").click()
time.sleep(3)
title = driver.title
print(title)
try:
self.assertEqual("123是你_百度一下",title,msg="不相等")
except:
self.saveScreenShot(driver,"是你.png")
time.sleep(3)
HTML
作用:所有結果輸出到 HTML 報告中
import os
import sys
import time
import unittest
import HTMLTestRunner
def createsuite():
discovers = unittest.defaultTestLoader.discover("../Test", pattern="unitDemo*.py", top_level_dir=None)
print(discovers)
return discovers
if __name__=="__main__":
#1,創建一個文件夾
# 當前的路徑
curpath = sys.path[0]
# sys.path 是一個路徑集合數組
print(sys.path)
print(sys.path[0])
# 當前路徑下resultreport文件夾不存在的時候,就創建一個
if not os.path.exists(curpath+'/resultreport'):
os.makedirs(curpath+'/resultreport')
# 2,解決重復命名的問題
now = time.strftime("%Y-%m-%d-%H %M %S", time.localtime(time.time()))
print(time.time())
print(time.localtime(time.time()))
# 文件名是路徑加上文件的名稱
# 準備HTML報告輸出的文件
filename = curpath + '/resultreport/'+ now + 'resultreport.html'
# 打開 HTML 文件, wb 以寫的方式
with open(filename, 'wb') as fp:
# 括號里的參數是 HTML 報告里面的參數
runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=u"測試報告",
description=u"用例執行情況", verbosity=2)
suite = createsuite()
runner.run(suite)
數據驅動
安裝工具包:pip install ddt
from selenium import webdriver
import unittest
import time
from ddt import ddt, unpack, file_data, data
import sys, csv
def getTxt(file_name):
# ([貓, 貓_百度搜索], [狗, 狗_百度搜索], [豬, 豬_百度搜索])
rows = []
path = sys.path[0]
with open(path + '/data/' + file_name, 'rt',encoding='utf-8') as f:
readers = csv.reader(f, delimiter=',', quotechar='|')
next(readers, None)
for row in readers:
temprows=[]
# 貓, 貓_百度搜索
for i in row:
temprows.append(i)
rows.append(temprows)
return rows
def getCsv():
# 讀取 csv 文件
values = []
with open('data/test_help_json.csv', encoding='utf-8') as f:
f_scv = csv.reader(f)
next(f_scv)
for i in f_scv:
values.append(i)
return values
@ddt
class Baidu(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.driver.maximize_window()
self.verificationErrors=[]
self.accept_next_alert=True
def tearDown(self):
self.driver.quit()
self.assertEqual([],self.verificationErrors)
# json 數據
# 一次獲取一條
@unittest.skip("skipping")
@file_data('data/test_baidu_data.json')
def test_baidu1(self, value):
driver = self.driver
driver.get(self.base_url+"/")
driver.maximize_window()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(value)
driver.find_element_by_id("su").click()
time.sleep(3)
@unittest.skip("skipping")
@data("貓","狗","豬","pig")
# 使用 data 直接放入數據
def test_baidu2(self, value):
driver = self.driver
driver.get(self.base_url+"/")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(value)
driver.find_element_by_id("su").click()
self.assertEqual(value,driver.title,msg="不符合")
time.sleep(3)
@data(['豬',u'豬_百度百科'],['pig',u'pig_百度百科'])
@unpack
# 使用兩個參數需要加 unpack
def test_baidu3(self, value, expected_value):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(value)
driver.find_element_by_id("su").click()
time.sleep(3)
self.assertEqual(expected_value, driver.title, msg="與預期不符合")
print(expected_value)
print(driver.title)
time.sleep(3)
# 讀取 txt 文本
@data(*getTxt('test_helpddt.txt'))
@unpack
def test_baidu4(self, value, expected_value):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(value)
driver.find_element_by_id("su").click()
time.sleep(3)
self.assertEqual(expected_value, driver.title, msg="與預期不符合")
print(expected_value)
print(driver.title)
time.sleep(3)
# 讀取 json 文件
@data(*getCsv())
@unpack
def test_baidu5(self,value,expected_value):
driver = self.driver
driver.get(self.base_url+"/")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(value)
driver.find_element_by_id("su").click()
self.assertEqual(value,expected_value,msg="不匹配")
time.sleep(3)
if __name__=="__main__":
unittest.main()


浙公網安備 33010602011771號