对一个测试的系统,开始最佳的测试就是源代码级别的测试,也就是单元测试阶段,这个过程也被成为白盒测试。单元测试是最基本也是最底层的测试类型,单元测试应用最基本的软件代码,如类,函数。方法等,单元测试通过可执行的断言检查被测单元的输出是否满足预期结果。在测试金字塔的理论上来说,越往下的测试投入资源越高,得到的回报率越大。
1、测试金字塔模型初识
最顶端为UI测试,中间为接口测试,最底部为单元测试。
2、白盒测试理论
5、unitest是单元测试框架,使用它的注意事项:
1)所有的测试用例都必须在test包下
2)每个测试模块都应该是以test_模块名称来命名
3)测试类建议以Test开头
4)每个测试类必须继承unittest模块中的TestCase类,这样就可以直接调用里面的方法(若是不继承,就直接采用对象进行类的实例化再调用里面的方法)
5)在测试类里面编写的方法叫测试方法,测试方法必须是以test开头的
6、unittest组件
测试用例:就是测试类里面编写的测试方法
测试固件:初始化和清理,使用到的方法分别是setUp()和tearDown()
测试套件:就是测试用例的集合,在一个测试套件中可以有很多的测试用例,它的英文单词是TestSuite
测试执行:TestRunner,执行测试套件或者测试用例
测试报告:TestReport,就是执行所有测试用例后的结果信息
7、测试固件
1)setUp() and tearDown():在一个测试类里面,有多少个测试用例,它就会被执行多少次
2)setUpClass() and tearDownClass():是类方法,不管测试类里面有多少测试用例,它只会执行一次
8、unittest的入门示例
1 import unittest 2 from selenium.webdriver.common.by import By 3 from selenium.webdriver.common.action_chains import ActionChains 4 import time as t 5 6 def add(a,b): 7 return a+b 8 9 class TestAdd(unittest.TestCase): 10 def test_add_int(self): 11 assert add(3,5)==8
9、百度首页测试示例(test_baidu),测试固件每次执行
1 import unittest 2 from selenium import webdriver 3 from selenium.webdriver.common.by import By 4 from selenium.webdriver.common.action_chains import ActionChains 5 from test.init import Init 6 import time as t 7 8 class TestBaidu(Init): 9 def setUp(self) -> None: 10 self.driver = webdriver.Chrome() 11 self.driver.maximize_window() 12 self.driver.get("https://www.baidu.com/") 13 14 15 def tearDown(self) -> None: 16 self.driver.quit() 17 18 19 def test_baidu_title(self): 20 '''百度首页:验证百度的title是否正确''' 21 # assert self.driver.title=="百度一下,你就知道" 22 self.assertEqual(self.driver.title, "百度一下,你就知道") 23 24 25 def test_baidu_url(self): 26 '''百度首页:验证百度的网址是否正确''' 27 # 浏览器输入网址必须为https,域名后边必须有斜杠 28 # assert self.driver.current_url=="https://www.baidu.com/" 29 self.assertEqual(self.driver.current_url, "https://www.baidu.com/") 30 31 32 def test_baidu_so(self): 33 '''百度首页:验证搜索框输入的关键字是否是接口测试''' 34 so = self.driver.find_element(By.ID, 'kw') 35 so.send_keys("接口测试") 36 # assert so.get_attribute("value")=="接口测试" 37 self.assertEqual(so.get_attribute("value"), "接口测试") 38 39 40 def test_baidu_enabled(self): 41 '''百度首页:验证搜索框是否可编辑''' 42 so = self.driver.find_element(By.ID, 'kw') 43 self.assertTrue(so.is_enabled()) 44 45 def test_baidu_displayed(self): 46 '''百度首页:验证关于百度的字条是否可见''' 47 so = self.driver.find_element(By.LINK_TEXT, '关于百度') 48 self.assertTrue(so.is_displayed()) 49 50 def test_baidu_setting(self): 51 '''百度首页:验证百度首页的设置的搜索设置是否打开''' 52 t.sleep(3) 53 setting=self.driver.find_element(By.XPATH,'//*[@id="s-usersetting-top"]') 54 action=ActionChains(driver=self.driver) 55 action.move_to_element(setting).perform() 56 self.driver.find_element(By.XPATH,'//*[@id="s-user-setting-menu"]/div/a[1]/span').click() 57 t.sleep(3) 58 soSet=self.driver.find_element(By.XPATH,'//*[@id="wrapper"]/div[6]/div/div/ul/li[1]') 59 # assert devText.text=="搜索设置" 60 self.assertEqual(soSet.text,"搜索设置") 61 62 if __name__ == '__main__': 63 unittest.main()
9、使用setUpClass() and tearDownClass()类的百度首页测试,测试固件只执行一次
1 import unittest 2 from selenium import webdriver 3 from selenium.webdriver.common.by import By 4 from selenium.webdriver.common.action_chains import ActionChains 5 from test.init import Init 6 import time as t 7 8 class TestBaidu(Init): 9 class TestBaidu(Init): 10 #使用setUpClass()方法 11 @classmethod 12 def setUpClass(cls) -> None: 13 cls.driver = webdriver.Chrome() 14 cls.driver.maximize_window() 15 cls.driver.get('http://www.baidu.com') 16 cls.driver.implicitly_wait(30) 17 #使用tearDownClass()类方法 18 @classmethod 19 def tearDownClass(cls) -> None: 20 cls.driver.quit() 21 22 23 def test_baidu_title(self): 24 '''百度首页:验证百度的title是否正确''' 25 # assert self.driver.title=="百度一下,你就知道" 26 self.assertEqual(self.driver.title, "百度一下,你就知道") 27 28 29 def test_baidu_url(self): 30 '''百度首页:验证百度的网址是否正确''' 31 # 浏览器输入网址必须为https,域名后边必须有斜杠 32 # assert self.driver.current_url=="https://www.baidu.com/" 33 self.assertEqual(self.driver.current_url, "https://www.baidu.com/") 34 35 36 def test_baidu_so(self): 37 '''百度首页:验证搜索框输入的关键字是否是接口测试''' 38 so = self.driver.find_element(By.ID, 'kw') 39 so.send_keys("接口测试") 40 # assert so.get_attribute("value")=="接口测试" 41 self.assertEqual(so.get_attribute("value"), "接口测试") 42 43 44 def test_baidu_enabled(self): 45 '''百度首页:验证搜索框是否可编辑''' 46 so = self.driver.find_element(By.ID, 'kw') 47 self.assertTrue(so.is_enabled()) 48 49 def test_baidu_displayed(self): 50 '''百度首页:验证关于百度的字条是否可见''' 51 so = self.driver.find_element(By.LINK_TEXT, '关于百度') 52 self.assertTrue(so.is_displayed()) 53 54 def test_baidu_setting(self): 55 '''百度首页:验证百度首页的设置的搜索设置是否打开''' 56 t.sleep(3) 57 setting=self.driver.find_element(By.XPATH,'//*[@id="s-usersetting-top"]') 58 action=ActionChains(driver=self.driver) 59 action.move_to_element(setting).perform() 60 self.driver.find_element(By.XPATH,'//*[@id="s-user-setting-menu"]/div/a[1]/span').click() 61 t.sleep(3) 62 soSet=self.driver.find_element(By.XPATH,'//*[@id="wrapper"]/div[6]/div/div/ul/li[1]') 63 # assert devText.text=="搜索设置" 64 self.assertEqual(soSet.text,"搜索设置") 65 66 if __name__ == '__main__': 67 unittest.main()
10、assert的常用方式:
assertEqual():比较的是两个对象的==关系
assertIn():比较的是两个对象的包含关系
assertIs():比较两个字符串的内存地址
assertTrue()
assertFalse()
11、测试固件的分离
在UI自动化测试中,所有的测试固件的部分的代码都是相同的,所以为了避免重复代码,提高效率,采用了测试固件分离的思想,使用继承的思想,把测试固件分离,这样的
好处是只需要在一个地方维护测试固件,而不是多个地方维护。其他的测试类只需要继承测试固件就可以使用了。
把测试固件分离到init.py里面,代码具体如下:
1 import unittest 2 from selenium import webdriver 3 4 class Init(unittest.TestCase): 5 def setUp(self) -> None: 6 self.driver=webdriver.Chrome() 7 self.driver.maximize_window() 8 self.driver.get("https://www.baidu.com/") 9 10 def tearDown(self) -> None: 11 self.driver.quit()
在其它测试模块可中导入这个Init类,然后再继承这个类,具体代码如下:
1 import unittest 2 from selenium import webdriver 3 from selenium.webdriver.common.by import By 4 from selenium.webdriver.common.action_chains import ActionChains 5 #测试固件分离思想,导入Init类 6 from test.init import Init 7 import time as t 8 #在测试类中继承Init类 9 class TestBaidu(Init): 10 def setUp(self) -> None: 11 self.driver=webdriver.Chrome() 12 self.driver.maximize_window() 13 self.driver.get("https://www.baidu.com/") 14 15 def tearDown(self) -> None: 16 self.driver.quit() 17 18 def test_baidu_title(self): 19 '''百度首页:验证百度的title是否正确''' 20 # assert self.driver.title=="百度一下,你就知道" 21 self.assertEqual(self.driver.title,"百度一下,你就知道") 22 23 def test_baidu_url(self): 24 '''百度首页:验证百度的网址是否正确''' 25 #浏览器输入网址必须为https,域名后边必须有斜杠 26 # assert self.driver.current_url=="https://www.baidu.com/" 27 self.assertEqual(self.driver.current_url,"https://www.baidu.com/") 28 if __name__ == '__main__': 29 unittest.main()
12、新浪首页示例
1 import unittest 2 from selenium import webdriver 3 from selenium.webdriver.common.by import By 4 from selenium.webdriver.common.action_chains import ActionChains 5 import time as t 6 7 class TestSina(unittest.TestCase): 8 def setUp(self) -> None: 9 self.driver=webdriver.Chrome() 10 self.driver.maximize_window() 11 self.driver.get("https://mail.sina.com.cn/#") 12 self.driver.implicitly_wait(30) 13 14 def tearDown(self) -> None: 15 self.driver.quit() 16 17 def test_username_null(self): 18 '''新浪首页:验证用户名为空时,直接登录时的提示信息是否正确''' 19 self.driver.find_element(By.CLASS_NAME, "loginBtn").click() 20 devText = self.driver.find_element(By.XPATH,'/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[1]') 21 self.assertEqual(devText.text, '请输入邮箱名') 22 23 def test_email_error(self): 24 '''新浪首页:验证用户名的格式错误时登录的提示信息是否正确''' 25 self.driver.find_element(By.ID, 'freename').send_keys("dgg") 26 self.driver.find_element(By.ID, 'freepassword').send_keys("fhsk") 27 self.driver.find_element(By.CLASS_NAME, "loginBtn").click() 28 devText = self.driver.find_element(By.XPATH,'/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[1]') 29 self.assertEqual(devText.text, '您输入的邮箱名格式不正确') 30 31 def test_username_password_error(self): 32 '''新浪首页:验证用户名和密码错误时登录的提示信息是否正确''' 33 self.driver.find_element(By.ID, 'freename').send_keys("134467@sina.com") 34 self.driver.find_element(By.ID, 'freepassword').send_keys("fhsk") 35 self.driver.find_element(By.LINK_TEXT, "登录").click() 36 t.sleep(5) 37 devText = self.driver.find_element(By.XPATH,'/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[1]') 38 t.sleep(3) 39 self.assertEqual(devText.text, '登录名或密码错误') 40 41 if __name__ == '__main__': 42 unittest.main()
13、参数化
当一个测试场景,它的测试步骤相同,测试数据不一样的时候,那么就可以使用参数化的思想来解决。
在unittest测试框架中,参数化需要借助第三方的库parameterized,先使用命令pip install parameterized安装 parameterized库,再具体应用参数化思想,代码如下:
1 import unittest 2 from selenium import webdriver 3 from selenium.webdriver.common.by import By 4 from selenium.webdriver.common.action_chains import ActionChains 5 from parameterized import parameterized,param 6 import time as t 7 8 class TestSina(unittest.TestCase): 9 def setUp(self) -> None: 10 self.driver=webdriver.Chrome() 11 self.driver.maximize_window() 12 self.driver.get("https://mail.sina.com.cn/#") 13 self.driver.implicitly_wait(30) 14 15 def tearDown(self) -> None: 16 self.driver.quit() 17 18 @parameterized.expand([ 19 param('','','请输入邮箱名'), 20 param('dgfa', 'fh','您输入的邮箱名格式不正确'), 21 param('gsd@sina.com', 'dhdhg', '登录名或密码错误') 22 ]) 23 def test_username_password_error(self,username,password,result): 24 '''新浪首页:验证用户名和密码异常时登录''' 25 self.driver.find_element(By.ID,'freename').send_keys(username) 26 self.driver.find_element(By.ID,'freepassword').send_keys(password) 27 self.driver.find_element(By.LINK_TEXT,"登录").click() 28 t.sleep(5) 29 devText=self.driver.find_element(By.XPATH,'/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[1]') 30 t.sleep(3) 31 self.assertEqual(devText.text,result) 32 33 if __name__ == '__main__': 34 unittest.main()
14、测试报告的生成
通过在test的包下创建一个run.py文件,导入第三方的库HTMLTestRunner,加载所有的测试模块来生成HTML报告,代码如下:
(unittest生成测试报告需要借助第三方的库HtmlTestRunner.py的文件)
1 import unittest 2 import os 3 import HTMLTestRunner 4 5 def allTests(): 6 #获取要执行的测试模块 7 suite=unittest.TestLoader().discover( 8 #start_dir指的是测试模块的路径 9 start_dir=os.path.dirname(__file__), 10 #pattern通过正则方式加载所有测试模块 11 pattern="test_*.py") 12 return suite 13 14 def run(): 15 filename=os.path.join(os.path.dirname(__file__),'report','index.html') 16 fp=open(filename,"wb") 17 runner=HTMLTestRunner.HTMLTestRunner( 18 stream=fp, 19 title='UI自动化测试', 20 description='ui test' 21 ) 22 runner.run(allTests()) 23 24 if __name__ == '__main__': 25 run()
生成的html报告如下: