目錄html
unit test:單元測試,能夠簡單粗暴地理解成用一段代碼去測試另一段代碼。unittest做爲Python單元測試框架之一,除了用來作單元測試以外,還能夠用來完成接口自動化,UI自動化(配合Selenium使用),自動化框架開發等。python
test fixture:測試用例執行前的準備工做以及測試用例執行完成後的清理工做。好比數據庫測試前要創建鏈接,測試後要關閉鏈接。mysql
test case:單元測試中最小的單元。web
test suite:測試套件是測試用例,測試套件或者二者的集合。一般被用來把測試用例組織起而後交給test runner執行。sql
test runner:測試執行器是執行用例並向用戶展現結果的組件。數據庫
登陸數據庫建立數據庫ums,在數據庫中建立表user_info,SQL語句以下:單元測試
create database ums; #status分爲active和inactive兩種 create table user_info( id int(10) primary key auto_increment, name char(15) not null, password char(100) not null, status char(10) not null) ENGINE=InnoDB DEFAULT CHARSET=utf8;
在Project下新建Python包 userManage ,在該包下建立Python文件userRegLogin.py。註冊時先判斷是否存在狀態爲active的用戶,不存在則更新信息到數據庫中。登陸時先判斷用戶狀態,若是爲active則去數據庫中查詢其密碼並比較密碼是否正確。userRegLogin.py的代碼以下:
#coding:utf-8 #導入MySQL驅動 import mysql.connector import warnings #定義類user_ange class user_manage(): #初始化 傳入兩個參數:用戶名和密碼 def __init__(self,name,passwd): self.name = name self.passwd = passwd #執行select SQL語句並返回結果 def execQuerySql(self,sql,arg): #臨時屏蔽告警ResourceWarning warnings.simplefilter("ignore", ResourceWarning) try: self.conn = mysql.connector.connect(host="127.0.0.1",user='root',database='ums',password='password') self.cursor = self.conn.cursor() self.cursor.execute(sql,[arg]) val = self.cursor.fetchone()[0] return val except Exception as e: print(e) finally: self.cursor.close() self.conn.close() #執行insert語句 def execUpdateSql(self,sql,args): warnings.simplefilter("ignore", ResourceWarning) try: self.conn = mysql.connector.connect(host="127.0.0.1",user='root',database='ums',password='password') self.cursor = self.conn.cursor() self.cursor.execute(sql,args) self.conn.commit() except Exception as e: print(e) finally: self.cursor.close() self.conn.close #判斷用戶是否存在 def userIsExist(self): sql1 = '''select count(*) from user_info where status='active' and name = %s''' userCount = self.execQuerySql(sql1,self.name) if userCount: return False else: return True #用戶註冊 def userReg(self): lenFlag = len(self.passwd) >=6 and len(self.passwd)<=10 #判斷是否存在同名用戶 if self.userIsExist(): #判斷密碼長度是否符合要求 if lenFlag: sql2 = '''insert into user_info values (null,%s,%s,'active');''' # self.cursor.execute(sql2,[self.name,self.passwd]) # self.conn.commit() args = [self.name,self.passwd] self.execUpdateSql(sql2,args) return "regSucess" else: return "passwordLenError" else: return "SameNameError" def isActive(self): sql3 = '''select status from user_info where name=%s;''' # self.cursor.execute(sql3,[self.name]) # ustatus = self.cursor.fetchone()[0] ustatus = self.execQuerySql(sql3,self.name) if ustatus == "active": return True else: return False #用戶登陸 def userLogin(self): ''' 用戶狀態爲active則校驗密碼是否正確 反之則拋出異常 ''' if self.isActive(): sql4 = '''select password from user_info where name=%s and status="active";''' pwdInDB = self.execQuerySql(sql4,self.name) if self.passwd == pwdInDB: return "loginSucess" else: return "passwordError" else: return "UserStatusError"
在userRegLogin.py文件末尾插入代碼並執行
if __name__ == '__main__': #實例化 user1 = user_manage("TestUser1","1234User1") user1.userReg()
登陸數據庫查看結果
mysql> select * from user_info; +----+-----------+-----------+--------+ | id | name | password | status | +----+-----------+-----------+--------+ | 3 | TestUser1 | 1234User1 | active | +----+-----------+-----------+--------+ 1 row in set (0.00 sec)
在Project下新建Python包testCases,在testCases下新建Python文件userRegTest.py,用來編寫測試用戶註冊功能的代碼。
[示例1]:userRegTest.py
#coding:utf-8 #導入unittest模塊 import unittest #從模塊userRegLogin中導入類user_manage from userManage.userRegLogin import user_manage #定義測試類,繼承於unittest.TestCase class regTest(unittest.TestCase): #測試方法或者叫測試用例必須以test開頭 #測試場景:密碼長度小於6 def test_pwdlen(self): user2 = user_manage("TestUser4","1234") self.assertEqual(user2.userReg(),"passwordLenError") #測試場景:正常註冊 def test_normalreg(self): user2 = user_manage("TestUser5","1234User") self.assertEqual(user2.userReg(),"regSucess") #執行test開頭的方法 if __name__ == '__main__': unittest.main()
[示例1運行結果]:
test fixture包含兩個方法,setUp(self)和tearDown(self)分別用於執行測試用例前的準備工做和執行完測試用例後的清理工做。這個兩個方法會在每一個用例的執行前或執行後被調用。把準備和清理工做和測試用例放在會致使不少重複代碼且不易維護。test fixture的使用場景究竟是什麼樣的呢?
場景一:好比說用戶註冊時會先校驗數據庫中是否存在狀態爲active的同名用戶,那麼該用例執行過以後,須要清理user_info表中的記錄,這個動做就是在tearDown(self)方法中完成的,不然再次執行就會報錯。
場景二:要驗證同名用戶名沒法註冊的異常場景,須要先註冊一次或者手動在user_info表裏面插入數據,這個動做就是在setUp(self)中完成的。
#coding:utf-8 #導入unittest模塊 import unittest #從模塊userRegLogin中導入類user_manage from userManage.userRegLogin import user_manage #定義測試類,繼承於unittest.TestCase class regTest(unittest.TestCase): #測試方法或者叫測試用例必須以test開頭 #測試場景:密碼長度小於6 def setUp(self): print("setUp run before test case") self.user1 = user_manage("TestUser1","1234") self.user2 = user_manage("TestUser2","TestUser2") self.user3 = user_manage("TestUser3","TestUser3") #註冊TestUser3 self.user3.userReg() def test_pwdlenerr_L1(self): print("test case:test_pwdlenerr_L1") res = self.user1.userReg() self.assertEqual(res,"passwordLenError") #測試場景:正常註冊 def test_regsucess_L0(self): print("test case:test_regsucess_L0") res = self.user2.userReg() self.assertEqual(res,"regSucess") #測試場景:用戶名重名 def test_regagain_L1(self): print("test case:test_regagain_L1") res = self.user3.userReg() self.assertEqual(res,"SameNameError") def tearDown(self): print("tearDown run after test case") sql = '''delete from user_info where name = %s''' self.user2.execUpdateSql(sql,[self.user2.name]) self.user3.execUpdateSql(sql,[self.user3.name]) if __name__ == '__main__': unittest.main()
[示例2運行結果]:
若是隻想在全部用例執行以前只執行一次準備工做怎麼操做呢?那就須要用到setUpClass() 和 tearDownClass()了。在這兩個方法內部能夠本身編寫函數實現準備工做或清理動做。
[示例3]:
#定義測試類,繼承於unittest.TestCase class regTest(unittest.TestCase): #測試方法或者叫測試用例必須以test開頭 #測試場景:密碼長度小於6 @classmethod def setUpClass(cls): print("setUpClass run before test case") def test_pwdlen(self): print("test case:test_pwdlen") self.user1 = user_manage("TestUser8","1234") res = self.user1.userReg() self.assertEqual(res,"passwordLenError") #測試場景:正常註冊 def test_normalreg(self): print("test case:test_normalreg") self.user2 = user_manage("TestUser10","123456") res = self.user2.userReg() self.assertEqual(res,"regSucess") @classmethod def tearDownClass(cls): # sql = '''delete from user_info where name = %s''' # sef.user2.execUpdateSql(sql,[self.user2.name]) print("tearDownClass run after test case") #執行test開頭的方法 if __name__ == '__main__': unittest.main()
注意:沒有清理動做若是想要用例跑成功的話須要手動刪除表裏對應的用戶信息或者修改註冊時傳入的name。
[示例3運行結果]::
在包testcases下新建Python文件userLoginTest.py,編寫測試登陸功能的代碼。
[ 示例4 ]:userLoginTest.py
#coding:utf-8 import unittest from userManage.userRegLogin import user_manage class loginTest(unittest.TestCase): #準備工做 def setUp(self): self.user4 = user_manage("TestUser4","TestUser4") self.user5 = user_manage("TestUser4","TestUser5") self.user6 = user_manage("TestUser6","TestUser6") #驗證登陸功能前須要先註冊 self.user4.userReg() #構造一個狀態爲inactive的用戶 self.user6.userReg() setStatus = '''update user_info set status="inactive" where name=%s;''' self.user6.execUpdateSql(setStatus,[self.user6.name]) #登陸成功測試 def test_loginsucess_L0(self): res = self.user4.userLogin() self.assertEqual(res,"loginSucess") #密碼錯誤測試 def test_pwdwrong_L0(self): res = self.user5.userLogin() self.assertEqual(res,"passwordError") #用戶狀態異常測試 def test_statuserr_L1(self): res = self.user6.userLogin() self.assertEqual(res,"UserStatusError") #清理工做 def tearDown(self): print("tearDown run after test case") #刪除用戶TestUser4,TestUser6 sql = '''delete from user_info where name = %s''' self.user4.execUpdateSql(sql,[self.user4.name]) self.user6.execUpdateSql(sql,[self.user6.name]) if __name__ == '__main__': unittest.main()
[ 示例4運行結果 ]:
unittest經過類unittest.TestSuite來組織測試用例。這個類返回測試用例或測試套的集合,它能夠被test runner執行。運行一個測試套至關於test runner把測試套迭代,而後執行每個測試用例。 一些方法能夠將用例添加到測試套中。
TestSuite和TestCase都有以下方法:
在Project下建立Python文件run.py,經過TestSuite來組織註冊登陸全部的用例並運行。
[ 示例5 ]:run.py
#coding:utf-8 import unittest #從testCase包裏面導入測試類 from testCases.userLoginTest import loginTest from testCases.userRegTest import regTest #構造測試套 def suite(): suite = unittest.TestSuite() suite.addTest(loginTest("test_loginsucess_L0")) suite.addTest(loginTest("test_pwdwrong_L0")) suite.addTest(loginTest("test_statuserr_L1")) suite.addTest(regTest("test_pwdlenerr_L1")) suite.addTest(regTest("test_regsucess_L0")) suite.addTest(regTest("test_regagain_L1")) return suite #運行測試用例 if __name__ == '__main__': runner = unittest.TextTestRunner() #調用test runner的run方法執行用例 runner.run(suite())
[ 示例5運行結果 ]: