专栏名称: Python学习交流
每天更新,更新python相关的知识。希望诸君有所收获!
目录
相关文章推荐
Python爱好者社区  ·  史上最强!PINN杀疯了 ·  昨天  
Python爱好者社区  ·  英伟达憾失DeepSeek关键人才?美国放走 ... ·  昨天  
Python爱好者社区  ·  1885页的Python完全版电子书 ·  3 天前  
Python开发者  ·  o3-mini 碾压 DeepSeek ... ·  5 天前  
Python开发者  ·  请立即拿下软考证书(政策风口) ·  4 天前  
51好读  ›  专栏  ›  Python学习交流

Python3+unitest自动化测试初探

Python学习交流  · 公众号  · Python  · 2019-04-22 20:49

正文

发现更多精彩

关注公众号

1、概念介绍

unit test:单元测试,可以简单粗暴地理解成用一段代码去测试另外一段代码。unittest作为Python单元测试框架之一,除了用来做单元测试之外,还可以用来完成接口自动化,UI自动化(配合Selenium使用),自动化框架开发等。

test fixture:测试用例执行前的准备工作以及测试用例执行完成后的清理工作。比如数据库测试前要建立连接,测试后要关闭连接。

test case:单元测试中最小的单元。

test suite:测试套件是测试用例,测试套件或者两者的集合。通常被用来把测试用例组织起然后交给test runner执行。

test runner:测试执行器是执行用例并向用户展示结果的组件。

2、准备工作

2.1、开发环境

  • 操作系统:Ubuntu 18.04.1 LTS

  • Python版本:3.7.0

  • 开发工具:PyCharm Edu

  • 本机已安装MySQL

  • 代码结构

2.2、创建数据库和表

登录数据库创建数据库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;

2.3、编写简单的注册登录代码

在Project下新建Python包 userManage ,在该包下创建Python文件userRegLogin.py。注册时先判断是否存在状态为active的用户,不存在则更新信息到数据库中。登录时先判断用户状态,如果为active则去数据库中查询其密码并比较密码是否正确。userRegLogin.py的代码如下:

#coding:utf-8#导入MySQL驱动import   mysql.connectorimport warnings
#定义类user_angeclass 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"

2.4、运行结果

在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)

2.5、测试场景

  1. 注册时存在同名状态为active的用户,返回SameNameError

  2. 注册成功,返回regSucess

  3. 注册密码长度不符合要求,返回passwordLenError

  4. 登录成功,返回loginSucess

  5. 登录密码不对,返回passwordError

  6. 登录状态为inactive,返回UserStatusError

3、一个简单的例子

在Project下新建Python包testCases,在testCases下新建Python文件userRegTest.py,用来编写测试用户注册功能的代码。
[示例1]:userRegTest.py

#coding:utf-8#导入unittest模块import unittest#从模块userRegLogin中导入类user_managefrom userManage.userRegLogin import user_manage#定义测试类,继承于unittest.TestCaseclass 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运行结果]:

  1. 测试类继承与unittest.TestCase

  2. 一个测试用例就是Python中的一个函数。

  3. 测试用例必须要以test开头

4、test fixture

test fixture包含两个方法,setUp(self)和tearDown(self)分别用于执行测试用例前的准备工作和执行完测试用例后的清理工作。这个两个方法会在每个用例的执行前或执行后被调用。把准备和清理工作和测试用例放在会导致很多重复代码且不易维护。test fixture的使用场景到底是什么样的呢?

  1. 场景一:比如说用户注册时会先校验数据库中是否存在状态为active的同名用户,那么该用例执行过之后,需要清理user_info表中的记录,这个动作就是在tearDown(self)方法中完成的,否则再次执行就会报错。

  2. 场景二:要验证同名用户名无法注册的异常场景,需要先注册一次或者手动在user_info表里面插入数据,这个动作就是在setUp(self)中完成的。

    4.1、setUp和tearDown示例

    把被测类实例化放在setUp()f方法里面。正常注册场景的清理动作:删除表user_info中对应的记录放在tearDown()方法中。接下来完善一下示例1中的代码:
    [示例2]:userRegTest.py

#coding:utf-8#导入unittest模块import unittest#从模块userRegLogin中导入类user_managefrom userManage.userRegLogin import user_manage
#定义测试类,继承于unittest.TestCaseclass 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运行结果]:

  1. 如果setUp()执行成功,那么不论用例是否执行成功,tearDown()都会执行。

  2. 如果setUp()执行失败,那么用例及tearDown()方法都不会被执行。

如果只想在所有用例执行之前只执行一次准备工作怎么操作呢?那就需要用到setUpClass() 和 tearDownClass()了。在这两个方法内部可以自己编写函数实现准备工作或清理动作。

4.2、setUpClass 和 tearDownClass

[示例3]:

#定义测试类,继承于unittest.TestCaseclass 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"






请到「今天看啥」查看全文