關於自動化測試框架,所需代碼技能,Java篇——參數配置與讀取.


前言:

  說在前邊。像我這種假期不出去浪,在這里乖乖寫文章研究代碼的人,絕壁不是因為愛學習,而是自己不知道去哪玩好,而且也不想玩游戲,看電視劇什么的,結果就無聊到看代碼了……

  至於如何解讀代碼,請把它當做一門語言,況且它就是語言 ,計算機的,那就當做是外國人的語言,可以翻譯成漢語的!

  例:system.out.print(" ") 翻譯:系統.輸出.打印(內容)。如是說!

本文介紹:

  • PropertiesCsvExcelJDBC

初級架構所需代碼之 參數配置與讀取——properties

  一般代碼中需要讀取配置有幾種方式,在此一一舉例說明吧~

  首先,比較常見的是讀取properties。一般,我們會將該文件存放在resource當中。

需要了解和使用的幾個主要方法:

1.getProperty ( String key),通過參數 key ,得到 key 所對應的 value。

2.load ( InputStream inStream),讀取配置,以供 getProperty ( String key) 來搜索。

3.setProperty ( String key, String value) ,set設置,也就是說設置key-value。

4.store ( OutputStream out, String comments),與 load 方法相反,該方法將 key-value 寫入到指定的文件中去。

5.clear (),清除所有裝載的key-value。該方法在基類中提供。

1和2搭配使用,3和4搭配使用。

實例解說

相比概念性的東西,伸手黨以及新手們更喜歡實例的東西來說明。

假如test.properties文件如下:

name=root
pass=admin
key=value

 

那么讀取和使用的方法如下(網上最多的文章是6種properties配置讀取方法,我這里推薦使用最常用的是這種):

Properties properties = new Properties();  //調用該方法,不要問為什么
InputStream in =null;  //初始化輸入流
in = Obejct.class.getResourceAsStream("/config.properties");  //獲取該路徑下的properties數據
try {
       properties.load(in);  //讀取數據
    } catch (IOException e) {
       e.printStackTrace();
    }
properties.getProperty("pass");  //根據key獲取values

最后獲取的值就是pass對應的admin.(注意你的路徑是否正確,以免報錯nullPoint

針對以上的例子,我們看到這樣的一句

Obejct.class.getResourceAsStream(path)  //path表示你的properties路徑

為了安全起見,更推薦將Obejct改寫成你的當前類名,比如 readProperties.class.getResourceAsStream("路徑").

 

參數讀取與使用——csv

TestNg中csv數據讀取與使用,可以利用此結構遍歷csv中的數據,讓用例循環執行,直到數據全部讀取完畢。

我們新建add.csv到你的任意目錄中,比如我的放在這里:

 

1.直接上代碼,首先是csv的數據:

2.創建兩個類,一個是基類,用來實現n1+n2=r1這樣的功能:

public class Calculator {
    public Float add(Float num1,Float num2){
        return num1+num2;
    }
}

一個是工具類,用來讀取csv中的數據:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;

public class CsvUtils implements Iterator<Object[]> {
    BufferedReader in;
    ArrayList<String> csvList=new ArrayList<String>();
    int rowNum=0;     //行數
    int columnNum=0;  //列數
    int curRowNo=0;   //當前行數
    String columnName[];  //列名
    /**
     * 在TestNG中由@DataProvider(dataProvider = "name")修飾的方法取csv數據時,
     * 調用此類構造方法(此方法會得到列名),
     * 返回給由@Test(dataProvider = "name")修飾的方法,如此
     * 反復到數據讀完為止
     * @param fileName 文件名
     * @throws IOException
     */
    public CsvUtils(String fileName) throws IOException{
        File directory=new File(".");
        String path=".src.main.java.page.testdata.";    //文件路徑
        String absolutePath=directory.getCanonicalPath()+path.replaceAll("\\.", Matcher.quoteReplacement("\\"))+fileName;
        System.out.println(absolutePath);   //打印路徑
        File csv=new File(absolutePath);
        in=new BufferedReader(new FileReader(csv)); //讀取csv數據
        while (in.ready()) {
            csvList.add(in.readLine());
            this.rowNum++;
        }
        String[] str=csvList.get(0).split(",");
        this.columnNum=str.length;
        columnName=new String[columnNum];
        //獲取列名
        for (int i = 0; i < columnNum; i++) {
            columnName[i]=str[i];
        }
        this.curRowNo++;
    }
    @Override
    public boolean hasNext() {
        // TODO Auto-generated method stub
        if(rowNum==0||curRowNo>=rowNum){
            try {
                in.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return false;
        }else{
            return true;
        }
    }
    /**
     * 獲取一組參數,即一行數據
     */
    @Override
    public Object[] next() {
        // TODO Auto-generated method stub
        Map<String,String> s=new TreeMap<String,String>();
        String csvCell[]=csvList.get(curRowNo).split(",");
        for(int i=0;i<this.columnNum;i++){
            s.put(columnName[i], csvCell[i]);
        }
        Object[] d=new Object[1];
        d[0]=s;
        this.curRowNo++;
        return d;
    }

    @Override
    public void remove() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("remove unsupported");
    }

}
CSVUtils

 

3.實現類

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

import core.utils.CsvUtils;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;


public class CsvTest{
    Calculator cal=new Calculator();

    @DataProvider(name="num")
    public Iterator<Object[]> Numbers() throws IOException{
        return (Iterator<Object[]>)new CsvUtils("add.csv");
    }
    @Test(dataProvider="num")
    public void testAdd(Map<String, String> data){
        float num1=Float.parseFloat(data.get("n1"));
        float num2=Float.parseFloat(data.get("n2"));
        float expectedResult=Float.parseFloat(data.get("r1"));
        Float actual=cal.add(num1, num2);
        Assert.assertEquals(actual, expectedResult);
    }
}

4.執行結果:

 

不要光看,自己敲一遍就知道什么意思了!

 

Excel數據的讀取

對於已經寫好了腳本的同學,多數采用的是這種數驅的形式,這種形式很方便維護自己的用例,完全不用打開編譯器,改改數據就好。

但是,它也同樣存在弊端,比如數據量相對大起來的時候,比如需要網絡調用的時候,我們都沒有很好的辦法去維護它,不過我們同樣要掌握這種數據讀取和使用的方法。

針對於Excel還有個要考慮的問題,那就是版本的問題,因為excel分為97-03,07+版,也就是文件后綴是.xls.xlsx的兩種版本(官網為什么不把14年前的版本干掉……要統一啊~),

所以,我們還要針對這兩種情況來整合封裝一個類,來實現根據后綴名判斷調用方法。

可以實現該功能的包有兩個:poijxl至於優勢和劣勢自己網上搜吧。

1.這里先介紹下POI的一些用法,首先它更適用於97-2008版本的Excel(Apache-POI官網);

可能會用到的字段說明:

  • HSSF - 提供讀寫Microsoft Excel XLS格式檔案的功能。
  • XSSF - 提供讀寫Microsoft Excel OOXML XLSX格式檔案的功能。
  • HWPF - 提供讀寫Microsoft Word DOC格式檔案的功能。
  • HSLF - 提供讀寫Microsoft PowerPoint格式檔案的功能。
  • HDGF - 提供讀Microsoft Visio格式檔案的功能。
  • HPBF - 提供讀Microsoft Publisher格式檔案的功能。
  • HSMF - 提供讀Microsoft Outlook格式檔案的功能。

關於Maven引用:

<!-- poi-ooxml同時支持XLS和XLSX兩種格式 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>

 思路:

創建讀取Excel-xlsx格式的類;

/**
     * 讀取2007-2013格式
     * @param filePath 文件路徑
     * @return excel以數組形式返回
     * @throws java.io.IOException
     */
    @SuppressWarnings("rawtypes")
    public static List<Map> readXLSX(String filePath) throws IOException {
        List<Map> valueList = new ArrayList<Map>();
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(filePath);
            XSSFWorkbook xwb = new XSSFWorkbook(fis);   // 構造 XSSFWorkbook 對象,strPath 傳入文件路徑
            XSSFSheet sheet = xwb.getSheetAt(0);            // 讀取第一章表格內容
            // 定義 row、cell
            XSSFRow row;
            // 循環輸出表格中的第一行內容   表頭
            Map<Integer, String> keys = new HashMap<Integer, String>();
            row = sheet.getRow(0);
            if (row != null) {
                //System.out.println("j = row.getFirstCellNum()::"+row.getFirstCellNum());
                //System.out.println("row.getPhysicalNumberOfCells()::"+row.getPhysicalNumberOfCells());
                for (int j = row.getFirstCellNum(); j <= row.getPhysicalNumberOfCells(); j++) {
                    // 通過 row.getCell(j).toString() 獲取單元格內容,
                    if (row.getCell(j) != null) {
                        if (!row.getCell(j).toString().isEmpty()) {
                            keys.put(j, row.getCell(j).toString());
                        }
                    } else {
                        keys.put(j, "K-R1C" + j + "E");
                    }
                }
            }
            // 循環輸出表格中的從第二行開始內容
            for (int i = sheet.getFirstRowNum() + 1; i <= sheet.getPhysicalNumberOfRows(); i++) {
                row = sheet.getRow(i);
                if (row != null) {
                    boolean isValidRow = false;
                    Map<String, Object> val = new HashMap<String, Object>();
                    for (int j = row.getFirstCellNum(); j <= row.getPhysicalNumberOfCells(); j++) {
                        XSSFCell cell = row.getCell(j);
                        if (cell != null) {
                            String cellValue = null;
                            if (cell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC) {
                                if (DateUtil.isCellDateFormatted(cell)) {
                                    cellValue = new DataFormatter().formatRawCellContents(cell.getNumericCellValue(), 0, "yyyy-MM-dd HH:mm:ss");
                                } else {
                                    cellValue = String.valueOf(cell.getNumericCellValue());
                                }
                            } else {
                                cellValue = cell.toString();
                            }
                            if (cellValue != null && cellValue.trim().length() <= 0) {
                                cellValue = null;
                            }
                            val.put(keys.get(j), cellValue);
                            if (!isValidRow && cellValue != null && cellValue.trim().length() > 0) {
                                isValidRow = true;
                            }
                        }
                    }

                    // 第I行所有的列數據讀取完畢,放入valuelist
                    if (isValidRow) {
                        valueList.add(val);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            fis.close();
        }
        return valueList;
    }
readXLSX

創建讀取Excel-xls格式的類;

 /**
     * 讀取97-2003格式
     * @param filePath 文件路徑
     * @throws java.io.IOException
     */
    @SuppressWarnings("rawtypes")
    public static List<Map> readXLS(String filePath) throws IOException{
        //返回結果集
        List<Map> valueList=new ArrayList<Map>();
        FileInputStream fis=null;
        try {
            fis=new FileInputStream(filePath);
            HSSFWorkbook wookbook = new HSSFWorkbook(fis);  // 創建對Excel工作簿文件的引用
            HSSFSheet sheet = wookbook.getSheetAt(0);   // 在Excel文檔中,第一張工作表的缺省索引是0
            int rows = sheet.getPhysicalNumberOfRows(); // 獲取到Excel文件中的所有行數­
            Map<Integer,String> keys=new HashMap<Integer, String>();
            int cells=0;
            // 遍歷行­(第1行  表頭) 作為Map里的key
            HSSFRow firstRow = sheet.getRow(0);
            if (firstRow != null) {
                // 獲取到Excel文件中的所有的列
                cells = firstRow.getPhysicalNumberOfCells();
                // 遍歷列
                for (int j = 0; j < cells; j++) {
                    // 獲取到列的值­
                    try {
                        HSSFCell cell = firstRow.getCell(j);
                        String cellValue = getCellValue(cell);
                        keys.put(j,cellValue);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            // 遍歷行­(從第二行開始)
            for (int i = 1; i < rows; i++) {
                // 讀取左上端單元格(從第二行開始)
                HSSFRow row = sheet.getRow(i);
                // 行不為空
                if (row != null) {
                    //准備當前行 所儲存值的map
                    Map<String, Object> val=new HashMap<String, Object>();

                    boolean isValidRow = false;

                    // 遍歷列
                    for (int j = 0; j < cells; j++) {
                        // 獲取到列的值­
                        try {
                            HSSFCell cell = row.getCell(j);
                            String cellValue = getCellValue(cell);
                            val.put(keys.get(j),cellValue);
                            if(!isValidRow && cellValue!=null && cellValue.trim().length()>0){
                                isValidRow = true;
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    //第I行所有的列數據讀取完畢,放入valuelist
                    if(isValidRow){
                        valueList.add(val);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            fis.close();
        }
        return valueList;
    }

    /**
     * 返回表內正確的內字符類型
     * @param cell 表格
     * @return
     */
    private static String getCellValue(HSSFCell cell) {
        DecimalFormat df = new DecimalFormat("#");
        String cellValue=null;
        if (cell == null)
            return null;
        switch (cell.getCellType()) {
            case HSSFCell.CELL_TYPE_NUMERIC:
                if(HSSFDateUtil.isCellDateFormatted(cell)){
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    cellValue=sdf.format(HSSFDateUtil.getJavaDate(cell.getNumericCellValue()));
                    break;
                }
                cellValue=df.format(cell.getNumericCellValue());
                break;
            case HSSFCell.CELL_TYPE_STRING:
                cellValue=String.valueOf(cell.getStringCellValue());
                break;
            case HSSFCell.CELL_TYPE_FORMULA:
                cellValue=String.valueOf(cell.getCellFormula());
                break;
            case HSSFCell.CELL_TYPE_BLANK:
                cellValue=null;
                break;
            case HSSFCell.CELL_TYPE_BOOLEAN:
                cellValue=String.valueOf(cell.getBooleanCellValue());
                break;
            case HSSFCell.CELL_TYPE_ERROR:
                cellValue=String.valueOf(cell.getErrorCellValue());
                break;
        }
        if(cellValue!=null&&cellValue.trim().length()<=0){
            cellValue=null;
        }
        return cellValue;
    }
readXLS

根據文件名選擇執行對應的類;

/**
     * 根據文件名自動識別讀取方式
     * 同時支持xls及xlsx格式的Excel數據讀取
     *
     * @param filepath 文件名:包含路徑及擴展名
     * @return 返回列表內容格式:
     * 每一行數據都是以對應列的表頭為key 內容為value 比如 excel表格為:
     * ===============
     * A | B | C | D
     * ===|===|===|===
     * 1 | 2 | 3 | 4
     * ---|---|---|---
     * a | b | c | d
     * ---------------
     * 返回  [{A=1, B=2, C=3, D=4}, {A=a, B=b, C=c, D=d}]
     * @throws java.io.IOException
     */
    public static List<Map> readExcel(String filepath) {
        List<Map> valueList = new ArrayList<Map>();

        try {
            if (new FileUtils().getuffix(filepath).equalsIgnoreCase("xlsx")) {
                valueList = ExcelUtils.readXLSX(filepath);
            }
            if (new FileUtils().getuffix(filepath).equalsIgnoreCase("xls")) {
                valueList = ExcelUtils.readXLS(filepath);
            } else {
                throw new ErrorOnSettingException("此文件不是Excel文件");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return valueList;
    }
readExcel

文件名工具類;

public class FileUtils {
    /**
     * 獲取文件名
     *
     * @param fileName 文件名包含擴展名
     * @return 返回獲取的文件名
     */
    public String getFileName(String fileName) {
        fileName = fileName.trim();
        String fName = fileName.substring(fileName.lastIndexOf("/") + 1);
        return fName;
    }
}
FileUtils

實現類:

ExcelUtils.readExcel(filepath);

 

 JDBC數據的讀取

本文最后要介紹JDBC的數據讀取,如何使用數據庫的數據到你的腳本中使用,也是數據參數驅動的一種常用方式;

針對數據量相對大的場景,首推數據庫來保存你的參數,也更方便維護;

相對於其他方式,jdbc在使用結束后,一定要關閉輸入流,就像webdriver使用結束后要有個webdriver.close()是一樣的,下邊的代碼中你也可以看到。

 假如數據庫中的數據如下:

數據庫配置與鏈接:

        // 數據庫類型
        private static String DBTYPE = "mysql";
        // 數據庫地址 格式:jdbc:mysql://ip:port/tablename?參數(可有可無,根據需要添加參數)
        private static String DB_URL = "jdbc:mysql://localhost:3306/antmember_test?characterEncoding=utf8&useSSL=true&serverTimezone=UTC";
        // 數據庫登錄賬號
        private static String USERNAME = "";
        // 數據庫登錄密碼
        private static String PASSWORD = "";
        // 數據庫表名
        private static String TABLENAME = "";
        // 鏈接數據庫
        private static Connection conn = null;
        // 向數據庫發送sql語句
        private static Statement statement = null;
        // 返回sql執行結果
        private static ResultSet resultSet = null;
        
        /**
         * 根據config配置信息,鏈接對應的數據庫
         */
        public static void dbConnect () {
        
            System.out.println("讀取數據庫配置並開始鏈接");
            try {
                if (DBTYPE.equals("mysql")) {
                    Class.forName("com.mysql.cj.jdbc.Driver");
                }
                if (DBTYPE.equals("oracle")) {
                    Class.forName("oracle.jdbc.driver.OracleDriver");
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

        }
配置與鏈接

數據庫的查詢:

 

        public static void dbSelect (String sql, String detail){
            dbConnect();
            try {
                //登錄數據庫
                conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
                //創建並執行sql語句
                statement = conn.prepareStatement(sql);
                //返回sql執行結果
                resultSet = statement.executeQuery(sql);

                JsonObject object = new JsonObject();
                JsonArray array = new JsonArray();

                while (resultSet.next()) {
                    JsonObject ob = new JsonObject();
                    ob.addProperty(detail, resultSet.getString(detail));
                    array.add(ob);
                }
                object.add("查詢結果:", array);
                System.out.println(object.toString());
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

        }
查詢

為了方便查看返回結果,我還用了json解析格式輸出到控制台中,同樣,你也可以輸出到你的文檔中,或者日志當中(json解析需要引入gson這個jar包,maven的方法我就不說了),另外,關於其他數據庫的鏈接方式如下:

# 連接MySql數據庫:Connection conn = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password");
# 連接Oracle數據庫:Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@host:port:database", "user", "password");
# 連接SqlServer數據庫:Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://host:port; DatabaseName=database", "user", "password");
# 其他參數如:useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC

 

使用:

    //我的表名:sm_user_info
    String sql = "SELECT * FROM sm_user_info WHERE id_type = 'git'";
       dbSelect(sql, "user_id");

控制台上的執行結果:

 

至此,本文介紹完畢。

當然還有很多可以講的東西,大家不妨如此這般的各種嘗試一下吧。

有問題可以留言下方,我會及時解答,並補充說明


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM