精华内容
下载资源
问答
  • 关键字驱动模型 源码: import csv import unittest from ddt import ddt, data, unpack def getCsvData(): value_rows = [] with open('./shuju.csv') as f: f_csv = csv.reader(f) next(f_c...

    数据表:
    在这里插入图片描述
    关键字驱动模型
    在这里插入图片描述
    源码:

    
    import csv
    import unittest
    from ddt import ddt, data, unpack
    def getCsvData():
        value_rows = []
        with open('./shuju.csv') as f:
            f_csv = csv.reader(f)
            next(f_csv)
            for r in f_csv:
                value_rows.append(r)
        return value_rows
    def add(x,y):
        sum =  x+y
        return sum
    @ddt
    class MyTestCase(unittest.TestCase):
        @data(*getCsvData())
        @unpack
        def test_something(self, searchTerm, searchResult):
            print(add(int(searchTerm),int(searchResult)))
    if __name__ == '__main__':
        unittest.main()
        ```
    
    
    展开全文
  • 关键字驱动测试是数据驱动测试的一种改进类型2. 主要关键字包括三类:被操作对象(Item)、操作(Operation)和值(value),用面向对象形式可将其表现为Item.Operation(Value)3. 将测试逻辑按照这些关键字进行分解,形成...

    一、原理及特点

    1.   关键字驱动测试是数据驱动测试的一种改进类型

    2.    主要关键字包括三类:被操作对象(Item)、操作(Operation)和值(value),用面向对象形式可将其表现为Item.Operation(Value)

    3.   将测试逻辑按照这些关键字进行分解,形成数据文件。

    4.    用关键字的形式将测试逻辑封装在数据文件中,测试工具只要能够解释这些关键字即可对其应用自动化

    二、准备

    使用工具:eclipse

    用到的第三方jar包:poi.jar(操作excel);selenium.jar

    理解难点:java反射机制;逐步分层

    三、框架构思

    1、编写脚本

    首先我们来写一个登陆开源中国的脚本

    public class Login_Script {

    public static WebDriver driver=null;

    public static void main(String []agrs) throws InterruptedException{

    //                启动火狐浏览器

    driver= new FirefoxDriver();

    //                最大化

    driver.manage().window().maximize();

    //                打开开源中国网址

    driver.get("http://www.oschina.net/");

    //                点击登录

    driver.findElement(By.xpath("//*[@id='OSC_Userbar']/a[1]")).click();

    //                输入用户名

    driver.findElement(By.xpath("//*[@id='f_email']")).sendKeys("XXXXXXB");

    //                输入密码

    driver.findElement(By.xpath("//*[@id='f_pwd']")).sendKeys("XXXXXXXA");

    //                点击登录按钮

    //                driver.findElement(By.xpath("//*[@id='login_osc']/table/tbody/tr[7]/td/input")).click();

    //                Thread.sleep(30);

    //                点击退出按钮

    driver.findElement(By.xpath("//*[@id='OSC_Userbar']/a[3]")).click();

    //                关闭浏览器

    driver.quit();

    }

    }

    2、脚本分析

    这是登陆的场景

    操作步骤

    第一步:启动浏览器

    第二步:输入网址

    第四步:点击登录

    第五步:输入用户名

    第六步:输入密码

    第七步:点击登录按钮

    第八步:点击退出

    第九步:关闭浏览器

    3、使用excel

    建立一个excel

    在java中创建一个操作excel的类 ,主要实现是对excel的读和写,主要代码如下:

    public class ExcelUtils {

    public static HSSFSheet ExcelSheet;

    public static HSSFWorkbook    ExcelBook;

    public static HSSFRow Row;

    public static HSSFCell    Cell;

    public static void setExcelFile(String Path,String    SheetName) throws Exception{

    FileInputStream    ExcelFile=new FileInputStream(Path);

    ExcelBook=new HSSFWorkbook(ExcelFile);

    ExcelSheet=ExcelBook.getSheet(SheetName);

    }

    public static void setCellData(String Result,  int RowNum, int ColNum,String Path) throws Exception{

    Row  = ExcelSheet.getRow(RowNum);

    Cell = Row.getCell(ColNum, Row.RETURN_BLANK_AS_NULL);

    if (Cell == null) {

    Cell = Row.createCell(ColNum);

    Cell.setCellValue(Result);

    } else {

    Cell.setCellValue(Result);

    }

    FileOutputStream fileOut = new FileOutputStream(Path);

    ExcelBook.write(fileOut);

    fileOut.flush();

    fileOut.close();

    }

    public static String getCellDate(int RowNum,int CloNum){

    Cell=ExcelSheet.getRow(RowNum).getCell(CloNum);

    String cellData=Cell.getStringCellValue();

    return cellData;

    }

    }

    4、新建一个ActionKeyWords类

    public class ActionKeyWords {

    public static WebDriver driver=null;

    //    启动浏览器并最大化

    public static void OpenBrowser (){

    driver= new FirefoxDriver();

    driver.manage().window().maximize();

    }

    //    打开开源中国网址

    public static void Navigate (){

    driver.get("http://www.oschina.net/");

    }

    //    点击登录

    public static void Login_Click (){

    driver.findElement(By.xpath("//*[@id='OSC_Userbar']/a[1]")).click();

    }

    //    输入用户名

    public static void Input_Name (){

    driver.findElement(By.xpath("//*[@id='f_email']")).sendKeys("XXXXXXA");

    }

    //    输入密码

    public static void Input_Password (){

    driver.findElement(By.xpath("//*[@id='f_pwd']")).sendKeys("XXXXXXB");

    }

    //    点击登录按钮

    public static void Login_Button (){

    driver.findElement(By.xpath("//*[@id='login_osc']/table/tbody/tr[7]/td/input")).click();

    }

    //    点击退出按钮

    public static void Logout_Click (){

    driver.findElement(By.xpath("//*[@id='OSC_Userbar']/a[3]")).click();

    }

    //    关闭浏览器

    public static void CloseBrowser (){

    driver.quit();

    }

    }

    5、修改Login_Script脚本.

    public class Login_Script {

    public static void main(String []agrs) throws Exception{

    ExcelUtils.setExcelFile("D:\\data\\TestData.xls", "steps");

    ActionKeyWords actionKeyWords= new ActionKeyWords();

    String Keywords=null;

    for(int RowNum=1;RowNum<=ExcelUtils.getLastRowNums();RowNum++){

    Keywords=ExcelUtils.getCellDate(RowNum, 3);

    if(Keywords.trim().equals("OpenBrowser")){

    actionKeyWords.OpenBrowser();

    }else if(Keywords.trim().equals("Navigate")){

    actionKeyWords.Navigate();

    }else if(Keywords.trim().equals("Login_Click")){

    actionKeyWords.Login_Click();

    }else if(Keywords.trim().equals("Input_Name")){

    actionKeyWords.Input_Name();

    }else if(Keywords.trim().equals("Input_Password")){

    actionKeyWords.Input_Password();

    }else if(Keywords.trim().equals("Login_Button")){

    actionKeyWords.Login_Button();

    }else if(Keywords.trim().equals("Logout_Click")){

    actionKeyWords.Logout_Click();

    }else if(Keywords.trim().equals("CloseBrowser")){

    actionKeyWords.CloseBrowser();

    }

    }

    }

    }

    这样代码的框架就基本已经搭建起来了,代码结构如下:

    四、结构优化

    1、优化Login_Script 类中的代码

    注:这里用到了反射机制

    public class Login_Script {

    public static ActionKeyWords actionKeyWords;

    public static String Keywords=null;

    public static Method[] method;

    public Login_Script(){

    actionKeyWords= new ActionKeyWords();

    method=actionKeyWords.getClass().getMethods();

    }

    public static void main(String []agrs) throws Exception{

    ExcelUtils.setExcelFile("D:\\data\\TestData.xls", "steps");

    new Login_Script();

    for(int RowNum=1;RowNum<=ExcelUtils.getLastRowNums();RowNum++){

    Keywords=ExcelUtils.getCellDate(RowNum, 3);

    login_action();

    }

    }

    public static void login_action(){

    for(int i=0;i

    //                    System.out.println(method[i].getName()+"     "+actionKeyWords+Keywords);

    if(method[i].getName().trim().equals(Keywords)){

    try {

    method[i].invoke(actionKeyWords);

    } catch (IllegalAccessException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    } catch (IllegalArgumentException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    } catch (InvocationTargetException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    }

    }

    }

    2、将程序中的常量统一管理

    例如:网页的地址,账户、密码,excel路径,这里我们在文件下面建立一个

    public class Contants {

    public static  String url="http://www.oschina.net/";

    public static String excelFile="D:\\data\\";

    public static String excelName="TestData.xls";

    public static String excelSheet="steps";

    public static int excelKWCloNum=3;

    public static String userName="XXXXXXXA";

    public static String userPassword="XXXXXB";

    }

    3、增加对象库

    下面我们看一下ActionKeyWords类中定位元素的路径 是在代码里面的,如果每次去修改的定位路径的是时候都要修改代码,为了便于维护,我们将这些元素的对象放在一个文件中,同时我们在Excel增加一列 Page Objects,这样程序根据Excel中的Page Objects,去文件中读取相应的元素,这里我们增加一个类OrpUtil,读取元素的对象

    # Home Page Objects

    Userbar_login=//*[@id='OSC_Userbar']/a[1]

    Userbar_logout=//div[@id='OSC_Userbar']/a[3]

    #Login Page Objects

    Input_name=//*[@id='f_email']

    Input_password=//*[@id='f_pwd']

    Login_button=//*[@id='login_osc']/table/tbody/tr[7]/td/input

    //OrpUtil类

    public class OrpUtil {

    public static String  readValue(String a){

    Properties pro=new Properties();

    String popath=Contants.ObjectReUrl;

    String value=null;

    try {

    InputStream in =new BufferedInputStream(new FileInputStream(popath));

    pro.load(in);

    value=pro.getProperty(a);

    } catch (FileNotFoundException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }catch (IOException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    return value;

    }

    }

    优化后的ActionKeyWords类

    public class ActionKeyWords {

    public static WebDriver driver=null;

    //    启动浏览器并最大化

    public static void OpenBrowser (String OR){

    System.setProperty("webdriver.chrome.driver", ".//server//chromedriver.exe");

    driver= new ChromeDriver();

    driver.manage().window().maximize();

    }

    //    打开开源中国网址

    public static void Navigate (String OR){

    driver.get(Contants.url);

    }

    //    点击登录

    public static void Login_Click (String OR){

    driver.findElement(By.xpath(OrpUtil.readValue(OR))).click();

    }

    //    输入用户名

    public static void Input_Name (String OR){

    driver.findElement(By.xpath(OrpUtil.readValue(OR))).clear();

    driver.findElement(By.xpath(OrpUtil.readValue(OR))).sendKeys(Contants.userName);

    }

    //    输入密码

    public static void Input_Password (String OR){

    driver.findElement(By.xpath(OrpUtil.readValue(OR))).click();

    driver.findElement(By.xpath(OrpUtil.readValue(OR))).sendKeys(Contants.userPassword);

    }

    //    点击登录按钮

    public static void Login_Button (String OR){

    driver.findElement(By.xpath(OrpUtil.readValue(OR))).click();

    }

    //    点击退出按钮

    public static void Logout_Click (String OR){

    try {

    Thread.sleep(300);

    driver.findElement(By.xpath(OrpUtil.readValue(OR))).click();

    } catch (InterruptedException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    //    关闭浏览器

    public static void CloseBrowser (String OR){

    driver.quit();

    }

    }

    这个OR的值是从Excel中读取的

    4、增加测试场景

    从Excel中我们可以看到,这操作是对应的用例编写中的我们的操作步骤,在用例设计的时候还有测试场景和结果,这里

    我们先增加个场景在EXCEL中增加一个名称为Suite的Sheet页

    我们程序的运行逻辑是循环读取Suite页中的Runmode,当为YES时根据对应的TestSuiteID去读取对应的Steps页中的操作在步骤,进行运行

    public static void main(String []agrs) throws Exception{

    ExcelUtils.setExcelFile(Contants.excelFile+Contants.excelName );

    new Login_Script();

    bResult = true;

    //循环读取suitSheet里面的值,找出运行的场景

    for(int j=1;j<=ExcelUtils.getLastRowNums(Contants.suitSheet);j++){

    String Runmode=ExcelUtils.getCellDate(j, Contants.suitRunmode,Contants.suitSheet);

    String suitTestSuiteId=ExcelUtils.getCellDate(j, Contants.suitTestSuiteId,Contants.suitSheet);

    int sRowNum;

    if(Runmode.equals("YES")){

    //根据stepTestSuiteId在caseSheet中循环查找相对应的执行步骤

    for(sRowNum=1;sRowNum<=ExcelUtils.getLastRowNums(Contants.caseSheet);sRowNum++){

    String stepTestSuiteId=ExcelUtils.getCellDate(sRowNum, Contants.stepTestSuiteId,Contants.caseSheet);

    System.out.println(ExcelUtils.getCellDate(sRowNum, Contants.excelKWCloNum,Contants.caseSheet));

    if(stepTestSuiteId.trim().equals(suitTestSuiteId)){

    Keywords=ExcelUtils.getCellDate(sRowNum, Contants.excelKWCloNum,Contants.caseSheet);

    r=ExcelUtils.getCellDate(sRowNum, Contants.excelPOCloNum,Contants.caseSheet);

    login_action(sRowNum);

    if(bResult == false){

    ExcelUtils.setCellData(Contants.fail, j, Contants.suitResult,Contants.excelFile+Contants.excelName, Contants.suitSheet);

    }

    }

    }

    if(bResult == true){

    ExcelUtils.setCellData(Contants.pass, j, Contants.suitResult,Contants.excelFile+Contants.excelName, Contants.suitSheet);

    }

    }else{

    System.out.println("没有要执行的用例");

    break;

    }

    }

    }

    5、增加测试结果

    在Excel中新增一列Resut

    在Login_Script中定义一个boolean类型的变量bResult,默认是true在各个地方try,,cacth,当出现异常的时候在bResult赋值为false,在Excel工具类中增加一个写入excel值得方法

    五、小结

    这样我们的关键字驱动框架就初步搭好了,下面我们回归一下基本思路:

    转自:http://my.oschina.net/hellotest/blog/531932

    展开全文
  • 自动化脚本之关键字驱动脚本

    千次阅读 2017-10-25 14:51:59
    第48贴:自动化脚本之关键字驱动脚本 关键字驱动实际上是比较复杂的数据驱动技术的逻辑扩展。将数据文件变成测试用例的描述,用一系列关键字指定要执行的任务。在关键字驱动技术中,假设测试者具有某些被测系统的...

    第48贴:自动化脚本之关键字驱动脚本

    关键字驱动实际上是比较复杂的数据驱动技术的逻辑扩展。将数据文件变成测试用例的描述,用一系列关键字指定要执行的任务。在关键字驱动技术中,假设测试者具有某些被测系统的知识,所以不必告诉测试者如何进行详细的动作,只是说明测试用例做什么,而不是如何做。这样在脚本中使用的是说明性方法和描述性方法。描述性方法将被测软件的知识建立在测试自动化环境中,这种知识包含在支持脚本中。


    例如,为完成在网页浏览时输入网址,一般的脚本需要说明在某某窗口的某某控件中输入什么字符;而在关键字驱动脚本中,可以直接是在地址栏中输入网址什么什么;甚至更简单,仅说明输入网址什么什么。

    关键字驱动脚本的数量不随测试用例的数量变化,而仅随软件规模而增加。这种脚本还可以实现跨平台的用例共享,只需要更改支持脚本即可。


    第49贴:脚本预处理

    预处理是一种或多种预编译功能,包括美化器、静态分析和一般替换。脚本的预处理是指脚本在被工具执行前必须进行编译。预处理功能通常需要工具支持,在脚本执行前自动处理。

    美化器是一种对脚本格式进行检查的工具,必要时将脚本转换成符合编程规范的要求。可以让脚本编写者更专注于技术性的工作。


    静态分析对脚本或表格执行更重要的检查功能,检查脚本中出现的和可能出现的缺陷。测试工具通常可以发现一些如拼写错误或不完整指令等脚本缺陷,这些功能非常有效。静态分析可以检查所有的缺陷和不当之处。类似于程序设计中的PC-Lint和LogiScope的功能。


    一般替换也就是宏替换。可以让脚本更明确,易于维护。使用替换时应注意不要执行不必要的替换。在进行调试时,应该注意缺陷可能是存在被替换的部分中,而不是原来的脚本中。

    展开全文
  • 数据驱动 数据和程序的分离,程序不变,数据变 from selenium import webdriver import time driver = webdriver.Firefox(executable_path = "d:\geckodriver") driver.get("http://www.bing.com") search_box = ...

    数据驱动

    数据和程序的分离,程序不变,数据变

    from selenium import webdriver
    import time
    driver = webdriver.Firefox(executable_path = "d:\geckodriver")
    driver.get("http://www.bing.com")
    search_box = driver.find_element_by_xpath("//input[@id='sb_form_q']")
    search_box.send_keys("大话西游之月光宝盒")
    query_button = driver.find_element_by_xpath("//input[@id='sb_form_go']")
    query_button.click()
    time.sleep(5)
    
    assert "周星驰" in driver.page_source
    driver.quit()
    

    请使用数据驱动的方式,实现访问网址、搜索框定位表达式、搜索词输入、搜索按钮定位表达式和断言值作为数据驱动的数据文件,然后执行测试脚本。
    测试脚本:

    from selenium import webdriver
    import time
    import os.path
    import sys
    
    def get_data_from_file(data_file_path,coding="utf-8"):
        if not os.path.exists(data_file_path):
            print("数据文件不存在!")
            sys.exit(0)
        test_data = []
        with open(data_file_path,'r',encoding=coding) as fp:
            for line in fp:
                if line.strip() == "":
                    continue
                test_data.append(line.split("||"))
        return test_data    
    test_data = get_data_from_file("f:\\urls.txt")
    #print(test_data)
    
    def test_step(url,searchbox_xpath,search_button_xpath,search_word,assert_word):
        driver = webdriver.Firefox(executable_path = "d:\geckodriver")
        driver.get(url)
        search_box = driver.find_element_by_xpath(searchbox_xpath)
        search_box.send_keys(search_word)
        query_button = driver.find_element_by_xpath(search_button_xpath)
        query_button.click()
        time.sleep(5)
        assert assert_word in driver.page_source
        driver.quit()
    
    for data in test_data:
        url = data[0].strip()
        searchbox_xpath = data[1].strip()
        search_button_xpath = data[2].strip()
        search_word = data[3].strip()
        assert_word = data[4].strip()
        print(url,searchbox_xpath,search_button_xpath,search_word,assert_word)
        test_step(url,searchbox_xpath,search_button_xpath,search_word,assert_word)
    
    

    数据文件:

    http://www.sogou.com||//input[@id='query']||//input[@id='stb']||神奇动物在哪里||叶茨
    http://www.bing.com||//*[@id='sb_form_q']||//*[@id='sb_form_go']||亚洲杯||国足
    

    在这里插入图片描述
    基于txt的数据驱动测试框架

    #encoding=utf-8
    from selenium import webdriver
    import time
    import traceback
    with open(u"data.txt") as fp:
        data = fp.readlines()
    
    
    driver = webdriver.Chrome(executable_path="d:\\chromedriver")
    #driver = webdriver.Ie(executable_path="d:\\IEDriverServer")
    test_result = []
    for i in range(len(data)):
        try:
            driver.get("http://www.baidu.com")
            driver.find_element_by_id("kw").send_keys(\
            data[i].split("||")[0].strip())
            driver.find_element_by_id("su").click()
            time.sleep()
            assert data[i].split("||")[1].strip() in driver.page_source
            test_result.append(data[i].strip()+u"||成功\n")
            print(data[i].split('||')[0].strip()+u"搜索测试执行成功")
        except AssertionError as e:
            print(data[i].split("||")[1].strip()+u"测试断言失败")
            test_result.append(data[i].strip()+u"||断言失败\n")
        except Exception as e:
            print(data[i].split("||")[1].strip()+u"测试执行失败")
            test_result.append(data[i].strip()+u"||异常失败\n")
            traceback.print_exc()
    
    with open(u"result.txt","w") as fp:
        fp.writelines(test_result)
    driver.quit()
    
    gloryroad test||光荣之路
    摔跤爸爸||阿米尔
    超人||电影
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    关键字驱动

    一个单词,能够映射到python程序中的一个函数的自动调用。单词可以放在数据文件中。
    测试脚本:

    from selenium import webdriver
    import time
    import os.path
    import sys
    
    def get_data_from_file(data_file_data,coding="utf-8"):
        if not os.path.exists(data_file_data):
            print("数据文件不存在!")
            sys.exit(0)
        test_data = []
        with open(data_file_data,"r",encoding=coding) as fp:
            for line in fp:
                if line.strip() == "":
                    continue
                test_data.append(line.split("||"))
        return test_data    
    test_data = get_data_from_file("f:\\testcase.txt")
    print(test_data)
    
    driver = None
    def open(browser_name):
        global driver
        if browser_name == "firefox":
            driver = webdriver.Firefox(executable_path = "d:\geckodriver")
    
    def visit(url):
        global driver
        driver.get(url)
    
    def input(xpath,content):
        global driver
        driver.find_element_by_xpath(xpath).send_keys(content)  
    
    def click(xpath):
        global driver
        driver.find_element_by_xpath(xpath).click()  
    
    def assert_f(assert_word):
        global driver
        assert assert_word in driver.page_source  
    
    def close():
        global driver
        driver.quit()
    
    for line in test_data:
        action = line[0]
        xpath = line[1]
        value = line[2].strip()        
        print(action,xpath,value)
        if xpath == "None" and value == "None":
            print("1",action+"()")
            exec(action+"()")
        elif xpath == "None" and value != "None":
            print("2",action+"(\""+value+"\")")
            exec(action+"(\""+value+"\")")
        elif xpath != "None" and value == "None":
            print("3",action+"(\""+xpath+"\")")
            exec(action+"(\""+xpath+"\")")
        else:
            print("4",action+"(\""+xpath+"\",\""+value+"\")")
            exec(action+"(\""+xpath+"\",\""+value+"\")")
            #action = "open"
            #value = "firefox"
            #open('firefox')
    

    数据文件:

    open||None||firefox
    visit||None||http://www.sogou.com
    input||//input[@id='query']||疯狂动物城
    click||//input[@id='stb']||None
    assert||None||古德温
    close||None||None
    

    在这里插入图片描述

    展开全文
  • 目录数据驱动优点缺点关键字驱动优点缺点 数据驱动 优点 > 被测系统/功能还处于开发阶段时,就能开始着手写测试脚本。 > 模块的脚本设计和数据集的使用可减少冗余的脚本 被测系统功能有变化时,只需修改...
  • 数据驱动 优点 > 被测系统/功能还处于开发阶段时,就能开始着手写测试脚本。   > 模块的脚本设计和数据集的使用可减少冗余的脚本 被测系统功能有变化时,只需修改与此业务功能相关的特定脚本。   >...
  • #混合驱动: 数据驱动+关键字驱动
  • 文章目录自动化测试的实施策略单元测试框架数据驱动设计模式核心原理适用场景代码示例关键字驱动设计模式混合模式驱动设计模式其他设计模式浅谈 自动化测试的实施策略 单元测试框架 数据驱动设计模式 核心原理 适用...
  •  一、关键字驱动KDT(Keyword-driven testing) 1、自动化测试框架发展的第三个阶段是关键字驱动测试框架阶段,它是当前比较流行的一种框架一,并且现在的自动化测试工具已经将关键字驱动框架融入到工具中。...
  • 关键字驱动测试是数据驱动测试的一种改进类型 主要关键字包括三类:被操作对象(Item)、操作(Operation)和值(value),用面向对象形式可将其表现为Item.Operation(Value) 将测试逻辑按照这些关键字进行分解,...
  • 摘要: 自动化测试框架demo,用关键字的形式将测试逻辑封装在数据文件中,测试工具解释这些关键字即可对其应用自动化 一、原理及特点 1. 关键字驱动测试是数据驱动测试的一种改进类型 2. 主要关键字包括三类...
  • 自动化测试框架demo,用关键字的形式将测试逻辑封装在数据文件中,测试工具解释这些关键字即可对其应用自动化 一、原理及特点 1. 关键字驱动测试是数据驱动测试的一种改进类型 2. 主要关键字包括三类:被操作...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 148
精华内容 59
关键字:

自动化测试之关键字驱动