Selenium2 Python 自动化测试实战学习笔记(四)

第五章          自动化测试模型

一个自动化测试框架就是一个集成体系,在这一体系中包含测试功能的函数库、测试数据源、测试对象识别标准,以及种可重用的模块。自动化测试框架在发展的过程中经历了几个阶段,线性测试、模块驱动测试、数据驱动测试、关键字驱动测试。

Python 提供了以下几种读取文件的方式。

l   read() 读取整个文件。

l   readline() 读取一行数据。

l   readlines() 读取所有行的数据。

下面通过读取csv 文件的方法来解决这个每次要读取多个信息的问题。

首先创建userinfo.csv 文件,通过WPS 表格或Excel 创建表格,文件另存为选择CSV 格式进行保存,注意不要直接修改Excel 的后缀名来创建CSV 文件,这样创建出来的并非真正的CSV 文件。

loop_reader.py

#coding=utf-8

import csv

 

my_file='userinfo.csv'

data=csv.reader(file(my_file,'rb'))

 

for user in data:

         print user

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

第六章          unittest 单元测试框架

6.1 分析带unittest 自动化测试脚本

   Baidu_with_unittes.py

# -*- coding: utf-8 -*-

from selenium import webdriver

from selenium.webdriver.common.by import By

from selenium.webdriver.common.keys importKeys

from selenium.webdriver.support.ui importSelect

from selenium.common.exceptions importNoSuchElementException

from selenium.common.exceptions importNoAlertPresentException

import unittest, time, re

 

class BaiduTest(unittest.TestCase):

   def setUp(self):

       self.driver = webdriver.Chrome()

       self.driver.implicitly_wait(30)

       self.base_url = "http://www.baidu.com/"

       self.verificationErrors = []

       self.accept_next_alert = True

 

   def test_baidu(self):

       driver = self.driver

       driver.get(self.base_url + "/")

       driver.find_element_by_id("kw").clear()

       driver.find_element_by_id("kw").send_keys("seleniumide")

       driver.find_element_by_id("su").click()

 

   def is_element_present(self, how, what):

       try:

           self.driver.find_element(by=how, value=what)

       except NoSuchElementException, e:

           return False

       return True

 

   def is_alert_present(self):

       try:

           self.driver.switch_to_alert()

       except NoAlertPresentException, e:

           return False

       return True

 

   def close_alert_and_get_its_text(self):

       try:

           alert = self.driver.switch_to_alert()

           alert_text = alert.text

           if self.accept_next_alert:

                alert.accept()

           else:

                alert.dismiss()

           return alert_text

       finally:

           self.accept_next_alert = True

           

   def tearDown(self):

       self.driver.quit()

       self.assertEqual([], self.verificationErrors)

 

if __name__ == "__main__":

unittest.main()

import unittest:首先要引入unittest框架包。

class BaiduTest(unittest.TestCase): Baidu 类继承unittest.TestCase类,从TestCase 类继承是告诉unittest 模块的方式,这是一个测试案例。

 

setUp 用于设置初始化工作,在每一个测试用例前先被执行,它与tearDown方法相呼应,后者在每一个测试用例执行后被执行。这里的初始化工作定义了浏览器启动和基础URL 地址。

 

定义空的verificationErrors 数组,脚本运行时的错误信息将被打印到这个数组中。

定义accept_next_alert 变量,表示是否继续接受下一个警告,初始化状态为Ture。

 

test_baidu 中放置的就是我们的测试脚本.

 

is_element_present 方法用来查找页面元素是否存在,通过find_element()来接收元素的定位方法(how)和定位值(what),如果定位到元素返回Ture,否则出现异常并返回Flase.

 

is_alert_present()方法用来处理弹出的警告框,用WebDriver 所提供的switch_to_alert()方法来捕捉警告框。如果捕捉到警告框返回Ture,否则异常,返回Flase。

 

close_alert_and_get_its_text()关闭警告并且获得警告信息。首先通过switch_to_alert()获得警告,通过.text 获得警告框信息。接着通过if 语句判断accept_next_alert 的状态,在setUp()已经初始化状态为Ture,如果为Ture,通过accept()接受警告。否则dismiss()忽略此警告。

 

tearDown 方法在每个测试方法执行后调用,这个方法用于完成测试用例执行后的清理工作,如退出浏览器、关闭驱动,恢复用例执行状态等。

 

在setUp()方法中定义了verificationErrors 为空数组,这里通过assertEqual()比较其是否为空,如果为空说明用例执行的过程过程中没有出现异常,否则将抛出AssertionError 异常。

if __name__ == "__main__":

unittest.main()

整个测试过程集成在unitest.main()模块中,其默认执行以test 开头的方法。

.py 文件有两种使用方式:作为模块被调用和直接使用。如果它等于"__main__"就表示是直接执行。

6.2unittest 单元测试框架解析

单元测试负责对最小的软件设计单元(模块)进行验证,它使用软件设计文档中对模块的描述作为指南,对重要的程序分支进行测试以发现模块中的错误。在Python 语言下有诸多单元测试框架,如unittest、Pytest、nose 等,其中unittest框架(原名PyUnit 框架)为Python 语言自带的单元测试框架,从Python 2.1 及其以后的版本都将PyUnit 作为一个标准模块放入Python 开发包中。

6.2.1 认识单元测试

         单元测试本身就是通过一段代码去验证另一个代码,所以不用单元测试框架也可以写单元测试.

count.py

#coding=utf-8

class Count:

    def__init__(self,a,b):

        self.a=a

        self.b=b

    defadd(self):

        returnself.a+self.b

    defsub(self):

       return self.a-self.b

         程序非常简单,创建一个Count 类用来计算两个数,通过__init__()方法对两个数进行初始化,接着常见add()方法返回两个数相加的结果, 接着常见sub()方法返回两个数相减的结果。

    通过手工方式所进行的单元测试可能是下面(testCount.py)这个样子的:

#coding=utf-8

from count import Count

class TestCount:

    def test_add(self):

        try:

           c=Count(4,5)

           add=c.add()

           assert(add==9),'Integer addition result error!'

        exceptAssertionError,msg:

            printmsg

        else:

            print"test pass!"

    deftest_sub(self):

        try:

           c=Count(9,2)

           sub=c.sub()

           assert(sub==7),'Integer addition result error!'

        exceptAssertionError,msg:

            printmsg

        else:

            print"test pass!"

mytest=TestCount()

mytest.test_add()

mytest.test_sub()

首先,引入count 文件下的Count 类,在test_add()方法中调用Count 类并传入两个参数4,5,调用Count类中的add()方法对两个参数做加法运算,通过assert()方法进行比较返回结果add 是否等于9;在test_sub()方法中调用Count 类并传入两个参数9,2,调用Count类中的sub()方法对两个参数做加法运算,通过assert()方法进行比较返回结果add 是否等于7,如果不相等则抛出自定义的“Integer addition result error!”异常信息,如果相等则打印“testpass!”。

由于测试代码甚至比被测试的代码还多,则是要采用unittest 这一自动测试框架来构造单元测试用例。通过unittest 来写单元测试:test_with_unittest.py

#coding=utf-8

from count import Count

import unittest

 

class TestCount(unittest.TestCase):

    def setUp(self):

        self.j=Count(4,5)

 

    def test_add(self):

        self.add=self.j.add()

        self.assertEqual(self.add,9)

 

    def test_sub(self):

        self.sub=self.j.sub()

       self.assertEqual(self.sub,-1)

       

    def tearDown(self):

        pass

 

if __name__=="__main__":

    unittest.main()

用import 语句引入unittest 模块。在setUp()方法中进行测试前的初始化工作,这里初始化了Count 类。在tearDown()方法中执行测试后的清除工作,因为没什么可清理的工作,通过pass 表示其为一个空的方法,什么也不做。setUp()和tearDown()都是TestCase类中定义的方法。

在test_add()中调用assertEqual()方法,对Count 类中的add()方法的返回值和预期值进行比较,确保两者是相等的,assertEqual()也是TestCase 类中定义的方法。

Unittest 提供了全局的main()方法,使用它可以很方便地将一个单元测试模块变成可以直接运行的测试脚本,main()方法使用TestLoader 类来搜索所有包含在该模块中的测试方法,并自动执行它们。

6.2.2 unittest 中的概念

         unittest 的文档中开篇就介绍了4 个重要的概念:test fixture, test case, test suite, test runner,我觉得只有理解了这几个概念,才能真正的理解单元测试的基本原理。

 

    Test case: 一个TestCase 的实例就是一个测试用例, 就是一个完整的测试流程,包括测试

前准备环境的搭建(setUp),实现测试过程的代码(run),以及测试后环境的还原(tearDown)。元测试(unittest)的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个功能进行验证。

 

test suite: 对一个功能的验证往往是需要多测试用例的,可以把多的测试用例集合在一起执行,这就产生了测试套件TestSuite 的概念,它用来组装单个测试用例,而且TestSuite 也可以嵌套TestSuite。

 

test runner: TextTestRunner 是来执行测试用例的,其中的run(test)用来执行TestSuite/TestCase。测试的结果会保存到TextTestResult 实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息。

 

test fixture: 对一个测试用例环境的搭建和销毁,是一个fixture,通过覆盖TestCase 的setUp()和tearDown()方法来实现.

TestSuit.py

#coding=utf-8

from count import Count

import unittest

 

class TestCount(unittest.TestCase):

    def setUp(self):

        self.j=Count(4,5)

 

    def test_add(self):

        self.add=self.j.add()

        self.assertEqual(self.add,9)

 

    def test_sub(self):

        self.sub=self.j.sub()

       self.assertEqual(self.sub,-1)

       

    def tearDown(self):

        pass

 

if __name__=="__main__":

    suite=unittest.TestSuite()

   suite.addTest(TestCount("test_add"))

   suite.addTest(TestCount("test_sub"))

 

    runner=unittest.TextTestRunner()

   runner.run(suite)

首先调用unittest所提供的TESTSuite()类,通过它下面的addTest()方法来添加TestCount类下面的test_add()测试方法。接着调用TextTestRunner()类,通过它下面的run()方法来运行suite所组装的测试用例。

6.2.3 编写单元测试用例

         unittest 框架的TestCase 类提供一些方法用检查比较和报告失败。

      方法                                  检查                   

assertEqual(a,b)                          a==b

assertNotEqual(a,b)                            a!=b

assertTrue(x)                             x is True

assertFalse(x)                                 x is False

assertIs(a,b)                              a is b

assertIsNot(a,b)                           a is not b

assertIsNotNone(x)                            x is None

assertIsNotNone(x)                            x is not None

assertIn(a,b)                             a in b

assertNotIn(a,b)                          a not in b

assertIsInstance(a,b)                         isinstance(a,b)

assertNotInstance(a,b)                        notisinstance(a,b)

 

    assertEqual(first, second, msg=None): 测试第一个和第二个是否是相等的,如果值不相等测试失败。msg 是否可选有参数,用于定义测试失败所要提示的信息。

assertNotEqual(first, second, msg=None): 它用于判断第一个与第二个是否是不相等的,如果相等测试失败。

asserEqual.py

#coding=utf-8

import unittest

classTest(unittest.TestCase):

    def setUp(self):

        number=input("Enter anumber:")

        self.number=number

    def test_case_10(self):

       self.assertEqual(self.number,10,msg='Your input is not 10!')

       

    def test_case_0(self):

        self.assertNotEqual(self.number,0,msg='Yourinput is not 0!')

    def tearDown(self):

        pass

if__name__=="__main__":

       unittest.main()

    #suit=unittest.TestSuite()

   #suit.addTest(Test("test_case_10"))

    #suit.addTest(Test("test_case_0"))

 

    #runner=unittest.TextTestRunner()

#runner.run(suit)

 

         assertTrue(expr, msg=None)

assertFalse(expr, msg=None)

用于测试表达式是true(或false)。

下面来实现一个判断是否为质数功能,所谓的质数(又叫素数)是指只能被1 和它本身整除的数。

Count.py

#coding=utf-8

def is_prime(m):

    if m<=1:

        return False

    for i in range(2,m):

        if m%i==0:

            return False

return True

关于判断是否为质数的实现很简单,当拿到一个数后如果能整除从2 与自身减1 之间的任意一个数说明其不为质数,返回False,否则返回Ture。

assertTrue.py

#coding=utf-8

import sys

sys.path.append("Lib")

from Lib import count

from count import is_prime

import unittest

 

class Test(unittest.TestCase):

    def setUp(self):

           pass

             deftest_is_prime(self):

            self.prime=is_prime(4)

           self.assertTrue(self.prime,msg="Is not prime!")

 

    def tearDown(self):

        pass

if __name__=="__main__":

    unittest.main()

    通过assertTrue()比较的结果一定不是Ture,那么msg 中所定义的信息将会被打印输出。

 

    assertIn(first, second, msg=None)

assertNotIn(first, second, msg=None)

测试第一个是否在第二个中,反过来讲第二个是否包含第一个。

定义字符串a 为“hello”,b 为“hello world”。通过assertIn 判断b 是否包含a,如果不包含将打印msg 的定义的信息。

assertIn.py

#coding=utf-8

import unittest

 

class Test(unittest.TestCase):

    def setUp(self):

        pass

 

    def AssertIn_1(self):

        self.a="hello"

        self.b="helloworld"

       self.assertIn(self.a,self.b,msg="a is not b")

 

    def AssertNotIn_1(self):

        self.a="good"

        self.b="god god"

       self.assertNotIn(self.a,self.b,msg="a is b")

       

    def AssertIn_2(self):

        self.a="hello"

        self.b="hellworld"

       self.assertIn(self.a,self.b,msg="a is not b")

 

    def AssertNotIn_2(self):

        self.a="good"

        self.b="good god"

       self.assertNotIn(self.a,self.b,msg="a is b")

 

    def tearDown(self):

        pass

 

if __name__=="__main__":

   # unittest.main()

   suite=unittest.TestSuite()

  suite.addTest(Test("AssertIn_1"))

  suite.addTest(Test("AssertNotIn_1"))

  suite.addTest(Test("AssertIn_2"))

   suite.addTest(Test("AssertNotIn_2"))

 

   runner=unittest.TextTestRunner()

  runner.run(suite)

定义字符串a 为“hello”,b 为“hello world”。通过assertIn 判断b 是否包含a,如果不包含将打印msg 的定义的信息。

在使用单元测试框架时,我们只写了一个用例,这显然是不符合实际需求的,在实际的测试过程中真对一个功能,我们甚至要编写几个,甚至几十个测试用例。下面就来介绍如何组织这些测试用例。

调用了TestSuite()类和TextTestRunner()分别来组织和执行测试用例。这样做的好处是可以通过addTest()方法自由的添加想要被执行的用例。

 

assertIs(first, second, msg=None)

assertIsNot(first, second, msg=None)

测试第一个和第二个是否为同一对象。

 

assertIsNone(expr, msg=None)

assertIsNotNone(expr, msg=None)

测试表达式是否为None 对象。

 

assertIsInstance(obj, cls, msg=None)

assertNotIsInstance(obj, cls, msg=None)

测试对象(obj)是否有一个实例(cls)。


6.2.4 discover 更多测试用例

         单元测试用例可能就会达到上百个,对于这种情况test.py文件会变得很臃肿,需要把这些测试用例进行划分,分散到不同的文件中,这样便于维护。

         对test.py文件的测试用例进行拆分,拆分的目录结构如下:

                   ../test_object/all_testcase.py

                                        /testadd.py

                                        /testsub.py

                              /lib/count.py

  testadd.py

import sys

sys.path.append("TestFun")

from TestFun import count

from count import Count

import unittest

 

class TestAdd(unittest.TestCase):

   def  setUp(self):

           pass

       

   def  test_add(self):

           self.j=Count(2,3)

           self.add=self.j.add()

           self.assertEqual(self.add,5,msg='The two integer result not equal')

 

   def test_add1(self):

           self.j=Count(2.3,3.6)

           self.add=self.j.add()

           self.assertEqual(self.add,5.9,msg='The two float sum is not equal')

 

   def  test_add2(self):

           self.j=Count("hello"," world")

           self.add=self.j.add()

           self.assertEqual(self.add,"hello world",msg='The two stringresult is not equal')

 

   def   tearDown(self):

            pass

 

testSub.py

import sys

sys.path.append("TestFun")

from TestFunimport count

from countimport Count

import unittest

 

class TestSub(unittest.TestCase):

    def setUp(self):

            pass

       

    def test_sub(self):

            self.j=Count(2,3)

            self.sub=self.j.sub()

           self.assertEqual(self.sub,-1,msg='The two integer result not equal')

 

    def test_sub1(self):

            self.j=Count(4.3,3.3)

            self.sub=self.j.sub()

           self.assertEqual(self.sub,1,msg='The two float resutl is not equal')

 

    def  tearDown(self):

             pass

 

All_project.py

#coding=utf-8

import unittest

from  testAdd import TestAdd

from  testSub import TestSub

 

suite=unittest.TestSuite()

suite.addTest(TestAdd("test_add"))

suite.addTest(TestAdd("test_add1"))

suite.addTest(TestAdd("test_add2"))

 

suite.addTest(TestSub("test_sub"))

suite.addTest(TestSub("test_sub1"))

 

if__name__=="__main__":

       runner=unittest.TextTestRunner()

       runner.run(suite)

 

TestFun/__init__.py

import count

 

TestFun/count.py

#coding=utf-8

class Count:

   def __init__(self,a,b):

       self.a=a

       self.b=b

 

   def add(self):

       return self.a+self.b

 

   def sub(self):

       return self.a-self.b

 

在上同的代码中,创建testadd.py 和testsub.py 分别用于测试count.py 中的add()和subtraction()两个方法。在每个测试文件中,可以通过addTest()任意的加载当前要运行测试用例。

接着创建all_test.py 文件,在这个文件中首先导入不同的测试文件,通过addTest()来加载所有的测试文件下面的测试类下面的测试用例,最终通过TextTestRunner()类来运行所有用例。

这样的设计看上去很完美,当用例达到成百上千条时在all_test.py 文件中addTest()测试用例就变成了一条纯的体力活儿,那么有没有更好的办法unittest 可以自己识别不同测试文件不同测试类下面的测试用例呢。在TestLoader类中提供了discover()方法可以解决这个问题。

         TestLoader:该类根据各种标准负责加载测试用例,并它们返回给测试套件。正常情况下没有必要创建这个类的实例。unittest 提供了可以共享了defaultTestLoader 类,可以使用其子类和方法创建实例,所以我们可以使用其下面的discover()方法来创建一个实例。

           

discover(start_dir,pattern='test*.py',top_level_dir=None)

   找到指定目录下所有测试模块,并可递归查到子目录下的测试模块,只有匹配到文件名才能被加载。如果启动的不是顶层目录,那么顶层目录必须要单独指定。

start_dir :要测试的模块名或测试用例目录。

pattern='test*.py' :表示用例文件名的匹配原则。星号“*”表示任意多个字符。

top_level_dir=None:测试模块的顶层目录。如果没顶层目录(也就是说测试用例不是放在多级目录中),默认为None。

Discover.py

#coding=utf-8

importunittest

 

defcreatSuite():

    testunit=unittest.TestSuite()

   test_dir='C:\\Users\\ewang\\Desktop\\Python_Selenium2\\UnitTest\\Test_project'

   discover=unittest.defaultTestLoader.discover(test_dir,pattern='test*.py',top_level_dir=None)

 

    for test_suite in discover:

        for test_case in test_suite:

            testunit.addTest(test_case)

            print testunit

    return testunit

 

if__name__=="__main__":

    alltestname=creatSuite()

    runner=unittest.TextTestRunner()

    runner.run(alltestname)

创建creatsuite()函数用于查找指定条件的下的所有测试用例,并将其组装到测试套件中。调用discover()方法,首先通过test_dir 定义查找测试文件的目录,pattern 用来定义匹配测试文件的文件名,如果文件名以test 开头的.py 文件,那么就认为它是一个测试文件。top_level_dir 默认为None。discover()只能找到了测试文件,接下来通过for 循环来找到测试文件下的每一个测试用例,并且将其添加测试套件中。

         说明一个测试用例的创建规则:我们在实际的测试用开发中用例的创建也应该分两个阶段,

用例刚在目录下被创建,可命名为aa.py ,当用例创建完成并且运行稳定后再添加到测试套件中。那么可以将aa.py 重新命名为start_aa.py ,那么测试套件在运行时只识别并运行start 开头的.py 文件。对于文件名的匹配规则完全由discover()方法中的pattern 参数决定。

        

 

 

 

 

6.3用unittest 编写web 自动化

         在动手写脚本之后前,我们先来简单的规划一个测试项目的目录:

.../test_project/all_test.py

/test_case/test_baidu.py

/test_case/test_youdao.py

/report/log.txt

All_test.py

#coding=utf-8

import unittest

 

def creatSuite():

   testunit=unittest.TestSuite()

   test_dir="C:\\Users\\ewang\\Desktop\\Python_Selenium2\\UnitTest\\Project\\test_case"

   discover=unittest.defaultTestLoader.discover(test_dir,pattern="test*.py",top_level_dir=None)

 

   for test_suit in discover:

       for test_case in test_suit:

            testunit.addTest(test_case)

   return testunit

 

if __name__=="__main__":

   alltest=creatSuite()

   runner=unittest.TextTestRunner()

runner.run(alltest)

 

或者run_all.py:

import unittest

import sys

sys.path.append("test_case")

from test_case import testBaidu

from test_case import testYoudao

 

suite=unittest.TestSuite()

suite.addTest(testBaidu.MyTest("test_baidu"))

suite.addTest(testYoudao.MyTest("test_youdao"))

 

if __name__=="__main__":

      runner=unittest.TextTestRunner()

       runner.run(suite)

 

test_case/__init__.py

import testBaidu,testYoudao

 

/test_case/test_baidu.py

#coding=utf-8

from selenium importwebdriver

import unittest,time

 

classMyTest(unittest.TestCase):

   

    def setUp(self):

        self.driver = webdriver.Chrome()

        self.driver.maximize_window()

        self.driver.implicitly_wait(10)

        self.base_url ="http://www.baidu.com"

       

    def test_baidu(self):

        driver = self.driver

        driver.get(self.base_url +"/")

        driver.find_element_by_id("kw").clear()

       driver.find_element_by_id("kw").send_keys("unittest")

       driver.find_element_by_id("su").click()

        time.sleep(2)

        title = driver.title

        self.assertEqual(title,u"unittest_百度搜索")

 

    def tearDown(self):

        self.driver.quit()

 

/test_case/test_youdao.py

#coding=utf-8

from selenium importwebdriver

import unittest,time

 

classMyTest(unittest.TestCase):

    def setUp(self):

        self.driver = webdriver.Chrome()

        self.driver.maximize_window()

        self.driver.implicitly_wait(10)

        self.base_url ="http://www.youdao.com"

       

    def test_youdao(self):

        driver = self.driver

        driver.get(self.base_url +"/")

       driver.find_element_by_id("query").clear()

        driver.find_element_by_id("query").send_keys("webdriver")

       driver.find_element_by_id("qb").click()

        time.sleep(2)

        title = driver.title

        self.assertEqual(title,u"webdriver- 有道搜索")

 

    def tearDown(self):

        self.driver.quit()

 

保存测试结果:

    首先打开Windows 命令提示符,进入到.../test_project/目录下执行名命令:

                   >Python all_test.py >> report/log.txt2>&1

        Python all_test.py 通过Python 执行all_test 文件

               >>report/log.txt 将测试输出写入到report目录下的log.txt 文件中

file 2>&1 标准输出被重定向到文件file,然后错误输出也重定向到和标准输出一样,所以错误输出也写入文件file。

 

 

 

 

6.4 用例执行的疑惑

         用例执行的顺序:首先是同步测试问题,不同测试类测试方法的执行顺序的,同一目录下不同测试文件的执行顺序。

         默认加载顺序是根据ASCII 码的顺序,数字与字母的顺序为:0~9,A~Z,a~z

 

通过测试套件的addTest()根据需求来加载,可以确定执行顺序,但这只限制于单个文件,如果用例多了,最省力的还是直接使用main()来加载测试用例。discover()方法加载用例也是按照ASCII 码的从小到大的顺序来加载同一目录下测试文件的,这个就更难控制了,我们唯一能做的就是通过测试文件的命名来为其排列执行顺序。

 

有时候测试的业务多了就要对测试用例进行划分目录,例如我们下面的测试目录:

.../test_case/test_aa.py

/test_aaa/test_a.py

/test_aaa/test_ccc/test_c.py

/test_bbb/test_b.py

 

对于上面的目录结构,如果将discover()方法中start_dir 参数定义为“.../test_case/”目录,只能执行test_aa.py 文件,对于“/test_aaa/”、“/test_aaa/test_ccc/”和“/test_bbb/”等二级、三级目录下的用例将不会被执行。如果想被discover()读取执行非常简单,在目录下添加__init__.py 文件。

 

 

 

修改后的目录如下:test_project:UnitTest\Test_project

.../test_case/test_aa.py

/test_aaa/test_a.py

/test_aaa/__init__.py

/test_aaa/test_ccc/test_c.py

/test_aaa/test_ccc/__init__.py

/test_bbb/test_b.py

/test_bbb/__init__.py



你可能感兴趣的:(python,selenium,自动化测试,Seleniu2)