利用unittest组织测试脚本—全栈软件测试自动化(3)

发表于:2020-6-24 09:25

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:赵旭斌 余杰    来源:51Testing软件测试网原创

  1.2  更多自动化测试战术体验
  1.2.1  利用unittest组织测试脚本
  由于Selenium本身并没有提供一套完整的测试框架,因此我们选用unittest测试框架来进一步完善自动化测试脚本。下面是实现的程序。
   import unittest
  from selenium import webdriver
  class BookFlight(unittest.TestCase):
  def setUp(self):
  #实例化
  self.driver = webdriver.Firefox()
  def test_login(self):
  driver = self.driver
  driver.get("Mercury Tours登录页面")
  assert "Mercury Tours" in driver.title
  username_edit = driver.find_element_by_name("userName")
  password_edit = driver.find_element_by_name("password")
  login_button = driver.find_element_by_name("login")
  username_edit.send_keys("mercury")
  password_edit.send_keys("mercury")
  login_button.click()
  assert "Find a Flight" in driver.title
  def tearDown(self):
  self.driver.close()
  if __name__ == "__main__":
  unittest.main()
  运行这个自动化测试脚本,脚本运行结果如图1.16所示。可以看出脚本正常运行。
  图1.16  脚本运行结果
  与之前的例子有所不同的是,我们创建了一个新的BookFlight类并且继承了unittest. TestCase。一旦任何一个类继承了TestCase类,这个类就自动变为unittest单元测试类。类似于Java的JUnit,BookFlight类同样包括了setUp方法及tearDown方法。setUp方法通常代表一个类的初始化,它会在每一个test方法之前运行,所以我们会看到在此方法中加入了self.driver = webdriver.Firefox()。具体代码如下。
   def setUp(self):
     self.driver = webdriver.Firefox()
  这样做就无须在每一个test方法之前都创建一个driver对象了。此处将webdriver. Firefox()实例返回给self.driver。这样操作以后,此类中的其他方法都可以使用此driver实例了。
  至于tearDown方法,它和setUp方法的作用几乎一样,它会在每一个test方法之后运行,因此通常会把一些诸如退出、关闭之类的操作放入其中。此处我们加入了 self.driver.close(),这样我们就无须在每一个 test 方法之后加入关闭操作了。具体代码如下。
   def tearDown(self):
     self.driver.close()
  在Python编程中,通常我们使用全小写的方式对方法、变量等进行命名,如my_first_python_script,但是有两个特殊情况。其一,类的命名不遵循这个规则;其二,setUp是一个特殊方法,改为全部小写之后就不起作用了,这个方法相当于JUnit中的setUp,在每个test方法之前都会运行,是关键字,区分大小写。
  最后,查看这个脚本的核心部分,即test_login这个测试方法。具体代码如下。
  def test_login(self):
  driver = self.driver
  driver.get("Mercury Tours登录页面")
  assert "Mercury Tours" in driver.title
  username_edit = driver.find_element_by_name("userName")
  password_edit = driver.find_element_by_name("password")
  login_button = driver.find_element_by_name("login")
  username_edit.send_keys("mercury")
  password_edit.send_keys("mercury")
  login_button.click()
  assert "Find a Flight" in driver.title
  “driver = self.driver”这一行代码表示将driver对象指向之前setUp创建的实例对象,这样可使用driver完成后续的一些操作。
  所有方法名必须要以test开头,否则PyUnit不会执行这个方法,因为PyUnit会把这个方法作为普通方法而不是测试方法。
  当然,在Python中,除了unittest之外,还有另外两个非常棒的单元测试框架—Nose和PyTest,有兴趣的读者可以尝试一下。一旦学会了unittest,你很快就能上手其他框架。
  1.2.2  测试用例的数据驱动
  代码片段如下。
   import unittest
  from selenium import webdriver
  class BookFlight(unittest.TestCase):
  def __init__(self,username,password):
  unittest.TestCase.__init__(self, methodName='test_login')
  self.username = username
  self.password = password
  def setUp(self):
  self.driver = webdriver.Firefox()
  def test_login(self):
  driver = self.driver
  driver.get("Mercury Tours登录页面")
  assert "Mercury Tours" in driver.title
  username_edit = driver.find_element_by_name("userName")
  password_edit = driver.find_element_by_name("password")
  login_button = driver.find_element_by_name("login")
  username_edit.send_keys(self.username)
  password_edit.send_keys(self.password)
  login_button.click()
  assert "Find a Flight" in driver.title, \
  "\n==> username:{0}\n==> password:{1}". \
  format(self.username,self.password)
  def tearDown(self):
  self.driver.close()
  if __name__ == "__main__":
  def data_driven_suite():
  data_repositories = [
  {'usr':'mercury','pwd':'mercury'},
  {'usr':'mercury1','pwd':'mercury'},
  {'usr':'mercury2','pwd':'mercury'},
  ]
  tests = []
  for data in data_repositories:
  tests.append(BookFlight(data['usr'],data['pwd']))
  return unittest.TestSuite(tests)
  runner = unittest.TextTestRunner()
  runner.run(data_driven_suite())
  首先,看BookFlight类,它增加了_ _init_ _方法。此方法就是一个类的构造器,当类被初始化的时候被执行。一个实例化只会执行一次,无论类中存在多少个test方法,而setUp方法会在每一个test方法前执行。继续看代码。
  def __init__(self,username,password):
  unittest.TestCase.__init__(self, methodName='test_login')
  self.username = username
  self.password = password
  在上面的代码中,首先指定需要执行的测试方法名test_login,并增加了两个参数,即username和password,这样做是为了从外部“实例化”测试类的时候,把用户名和密码传入此类中以达到参数化的目的。然后,如下面的代码片段所示,将脚本中的用户名和密码一并替换成了self.username和self.password。
   username_edit.send_keys(self.username)
  password_edit.send_keys(self.password)
  接着,再来看data_driven_suite这个方法,它是用于数据驱动的核心方法。
   def data_driven_suite():
  data_repositories = [
  {'usr':'mercury','pwd':'mercury'},
  {'usr':'mercury1','pwd':'mercury'},
  {'usr':'mercury2','pwd':'mercury'},
  ]
  tests = []
  for data in data_repositories:
  tests.append(BookFlight(data['usr'],data['pwd']))
  return unittest.TestSuite(tests)
  在以上代码中,首先创建了一个字典数组data_repositories,其中包含了3组用户名和密码。然后,创建了一个空的tests数组,如果不理解,可以把这个空的tests数组看作一个用于存放所有test库的数组,把需要执行的test全部放在里面。接着,用一个for循环遍历整个data_repositories中的3组用户名和密码,生成3组不同用户名和密码的test,并将其添加到tests库中。最后,将整个tests库合并成一个测试集(testsuite)并返回。
   runner = unittest.TextTestRunner()
  runner.run(data_driven_suite())
  上面的程序表示把整个suite传给runner.run函数,之后即可运行。通过以上方式即可完成3组数据驱动测试,测试结果如图1.17所示。
  图1.17  利用unittest框架执行的测试结果
  一共有3组测试,失败了两组,因为第二组和第三组的用户名与密码都是不正确的。同时,测试结果中输出了出错时所使用的数据,这是因为我们已经在脚本的“assert”中加入了日志输出功能。具体代码如下。
   assert "Find a Flight" in driver.title, \
  "\n==> username:{0}\n==> password:{1}". \
  format(self.username,self.password)
  在代码片段中,每行句末的符号“\”是Python中的续行符号。

查看《全栈软件测试自动化 Selenium和Appium (Python版)》全部连载章节
版权声明:51Testing软件测试网获得人民邮电出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号