簡體   English   中英

使用Selenium WebDriver,Selenium Grid和testNG運行並行測試

[英]Running Parallel Tests using Selenium WebDriver, Selenium Grid and testNG

這是我在SO上的第一篇文章。 我是具有Java初學者技能的新手Selenium用戶。

為您提供我們工作的背景; 我們正在使用頁面對象模型 我們所有的測試都使用單個DataProvider方法,該方法基於調用/使用DataProvider的測試用例名稱從“ .xlsx”文件中獲取其數據。

但是,我們不確定是否已按應有的方式聲明了ThreadLocal 而且,我們不確定getDriver()方法的聲明是否正確。 另一個問題是我們不確定是否應在setuptearDown方法上使用“ @BeforeTest” /“ @ AfterTest”“ @BeforeClass” /“ @ AfterClass”

遇到以下問題:

  1. 一項測試失敗,隨后的測試也失敗。
  2. 有時,要提取的測試數據不准確(拋出的列數據比預期的多)。


這是我們的CONFIGTESTBASE類:

public class ConfigTestBase {

    private static ThreadLocal<RemoteWebDriver> threadedDriver = null;
    private static XSSFSheet ExcelWSheet;
    private static XSSFWorkbook ExcelWBook;
    private static XSSFCell Cell;
    private static XSSFRow Row;
    private static final String Path_TestData = GlobalConstants.testDataFilePath;
    private static final String File_TestData = GlobalConstants.testDataFileName;

    @Parameters({"objectMapperFile"})
    @BeforeSuite
    public void setupSuite(String objectMapperFile) throws Exception {
        GlobalConstants.objectMapperDefPath = new File(objectMapperFile).getAbsolutePath();
        new Common().OverrideSSLHandshakeException();
    }

    @Parameters({"browserName"})
    @BeforeClass
    public void setup(String browserName) throws Exception {

        threadedDriver = new ThreadLocal<>();

        DesiredCapabilities capabilities = new DesiredCapabilities();

        if (browserName.toLowerCase().contains("firefox")) {
            capabilities = DesiredCapabilities.firefox();
            capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
            capabilities.setBrowserName("firefox");
            capabilities.setPlatform(Platform.WINDOWS);
        }

        if (browserName.toLowerCase().contains("ie")) {
            System.setProperty("webdriver.ie.driver","C:\\selenium\\IEDriverServer.exe");
            capabilities = DesiredCapabilities.internetExplorer();
            capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
            capabilities.setCapability(InternetExplorerDriver.FORCE_CREATE_PROCESS, false);
            capabilities.setBrowserName("internet explorer");
            capabilities.setPlatform(Platform.WINDOWS);
        }

        if (browserName.toLowerCase().contains("chrome")) {
            System.setProperty("webdriver.chrome.driver","C:\\selenium\\chromedriver.exe");
            capabilities = DesiredCapabilities.chrome();
            capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
            capabilities.setBrowserName("chrome");
            capabilities.setPlatform(Platform.WINDOWS);
        }

        if (browserName.toLowerCase().contains("safari")) {
            SafariOptions options = new SafariOptions();
            options.setUseCleanSession(true);
            capabilities = DesiredCapabilities.safari();
            capabilities.setCapability(SafariOptions.CAPABILITY, options);
            capabilities.setBrowserName("safari");
            capabilities.setPlatform(Platform.WINDOWS);
        }

        threadedDriver.set(new RemoteWebDriver(new URL(GlobalConstants.GRIDHUB), capabilities));

    }

    protected static RemoteWebDriver getDriver(){
        RemoteWebDriver driver = null;

        try {
            driver = threadedDriver.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return driver;
    }

    @AfterClass
    public void tearDown() throws Exception {
        getDriver().quit();
    }

    //This method is to set the File path and to open the Excel file, Pass Excel Path and Sheetname as Arguments to this method
    public void setExcelFile(String Path,String SheetName) throws Exception {
        try {
            // Open the Excel file
            FileInputStream ExcelFile = new FileInputStream(Path);

            // Access the required test data sheet
            ExcelWBook = new XSSFWorkbook(ExcelFile);
            ExcelWSheet = ExcelWBook.getSheet(SheetName);
        } catch (Exception e) {
            throw (e);
        }
    }

    //This method is to read the test data from the Excel cell, in this we are passing parameters as Row num and Col num
    @SuppressWarnings("static-access")
    public String getCellData(int RowNum, int ColNum) throws Exception{
        try{
            Cell = null;
            Cell = ExcelWSheet.getRow(RowNum).getCell(ColNum);
            Cell.setCellType(Cell.CELL_TYPE_STRING);
            return Cell.getStringCellValue();
        } catch (Exception e) {
            return "";
        }
    }

    //This method is to write in the Excel cell, Row num and Col num are the parameters
    @SuppressWarnings("static-access")
    public void setCellData(String textValue,  int RowNum, int ColNum) throws Exception    {
        try{
            Row  = ExcelWSheet.getRow(RowNum);
            Cell = Row.getCell(ColNum, Row.RETURN_BLANK_AS_NULL);
            if (Cell == null) {
                Cell = Row.createCell(ColNum);
                Cell.setCellValue(textValue);
            } else {
                Cell.setCellValue(textValue);
            }

            // Constant variables Test Data path and Test Data file name
            FileOutputStream fileOut = new FileOutputStream(Path_TestData + File_TestData);
            ExcelWBook.write(fileOut);
            fileOut.flush();
            fileOut.close();
        } catch (Exception e) {
            throw (e);
        }
    }

    @DataProvider(name="getDataFromFile")
    public Object[][] getDataFromFile(Method testMethod, ITestContext context) throws Exception {

        String[][] tabArray;
        int intCounter;
        int intRowCount = 0;
        int intRowCounter = 0;
        int intColCount = 0;
        int intColCounter;
        int intColDataCount = 0;
        int intColDataCounter = 0;
        String temp;

        String testName = testMethod.getName();
        String banner = context.getCurrentXmlTest().getParameter("banner");
        setExcelFile(Path_TestData + File_TestData, banner);

        //get number of data to be returned
        for(intCounter=0;intCounter<ExcelWSheet.getLastRowNum()+1;intCounter++){
            if(getCellData(intCounter, 1).equals(testName)) {
                if (intColCount == 0) {
                    intColCount = ExcelWSheet.getRow(intCounter).getLastCellNum() - 2;
                }
                intRowCount++;
            }
        }

        if(intRowCount == 0){
            System.out.println("\n*** Data for '" + testName + "' was not found.");
            throw new AssertionError("Data for '" + testName + "' was not found.");
        }

        for(intCounter=0;intCounter<ExcelWSheet.getLastRowNum()+1;intCounter++){
            if(getCellData(intCounter, 1).equals(testName)) {
                for(intColCounter=2;intColCounter<intColCount+2;intColCounter++) {
                    temp = getCellData(intCounter,intColCounter);
                    if(temp != null && !temp.isEmpty()){
                        intColDataCount++;
                    }
                }
                //to exit FOR loop
                intCounter = ExcelWSheet.getLastRowNum()+1;
            }
        }

        //set data array dimension
        tabArray = new String[intRowCount][intColDataCount];

        for(intCounter=0;intCounter<ExcelWSheet.getLastRowNum()+1;intCounter++){
            if(getCellData(intCounter, 1).equals(testName)) {
                intRowCounter++;
                for(intColCounter=2;intColCounter<intColCount+2;intColCounter++) {
                    temp = getCellData(intCounter,intColCounter);
                    if(temp != null && !temp.isEmpty()){
                        tabArray[intRowCounter-1][intColDataCounter] = getCellData(intCounter,intColCounter);
                        intColDataCounter++;
                    }
                }
            }
        }

        return tabArray;

    }

}


這是一個示例測試類; 擴展CONFIGTESTBASE類...每個測試一個類:

public class Google6 extends ConfigTestBase {

    private Generic generic = null;
    private HomePage homePage = null;

    @BeforeMethod
    public void MethodInit(ITestResult result) throws Exception {
        generic = new Generic(getDriver());
        homePage = new HomePage(getDriver());
    }

    @Test(dataProvider="getDataFromFile")
    public void Google6(String execute, String url, String searchString) throws Exception {

        if(execute.toUpperCase().equals("YES")) {

            //navigate to application page
            generic.navigateToURL(url);

            //search
            homePage.search(searchString);

        } else {
            generic.log("Execute variable <> 'YES'. Skipping execution...");
            throw new SkipException("Execute variable <> 'YES'. Skipping execution...");
        }

    }
}


這是我們的套件文件; “ banner”參數用於在“ .xlsx”文件中查找特定的工作表:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="Full Test Suite - Firefox" parallel="classes" thread-count="5" verbose="1">
    <parameter name="objectMapperFile" value="mom.objectdef.properties" />

    <test name="Regression - Firefox">
        <parameter name="browserName" value="firefox" />
        <parameter name="banner" value="SAMPLE" />
        <classes>
            <class name="com.company.automation.web.app.testsuites.Google1" />
            <class name="com.company.automation.web.app.testsuites.Google2" />
            <class name="com.company.automation.web.app.testsuites.Google3" />
            <class name="com.company.automation.web.app.testsuites.Google4" />
            <class name="com.company.automation.web.app.testsuites.Google5" />
            <class name="com.company.automation.web.app.testsuites.Google6" />
        </classes>
    </test>

</suite>


關於如何使它起作用的任何建議?

1)您正在為每個測試類實例化一個新的ThreadLocal,因為它在BeforeClass批注中。 您應該同時聲明和實例化ThreadLocal:

private static ThreadLocal<RemoteWebDriver> threadedDriver = new ThreadLocal<>();

2)Excel解析邏輯是瘋狂的。 至少,您需要將其分成自己的類。 如果可能,請使用.csv文件而不是.xlsx文件,並使用諸如opencsv之類的文件進行解析; 它將震撼您的世界。 解析之后,您可以將其轉換為TestNG的DataProvider期望的內容。 像這樣:

public class CSVDataReader {
    private static final char DELIMITER = ',';
    private static final char QUOTE_CHAR = '\"';
    private static final char ESCAPE_CHAR = '\\';

    private static List<String[]> read(String filePath, boolean hasHeader) throws IOException {
        CSVReader reader;

        if (hasHeader) {
            // If file has a header, skip the header (line 1)
            reader = new CSVReader(new FileReader(filePath), DELIMITER, QUOTE_CHAR, ESCAPE_CHAR, 1);
        } else {
            reader = new CSVReader(new FileReader(filePath), DELIMITER, QUOTE_CHAR, ESCAPE_CHAR);
        }

        List<String[]> rows = reader.readAll();
        reader.close();

        return rows;
    }

    public static String [][] readCSVFileToString2DArray(String filePath, boolean hasHeader) throws IOException {
        List<String[]> rows = read(filePath, hasHeader);

        // Store all rows/columns in a two-dimensional String array, then return it
        String [][] csvData = new String[rows.size()][];

        int r = 0;
        for (String[] row : rows) {
            csvData[r++] = row;
        }

        return csvData;
    }
}

一次只做一件事time..I相信你已經交給該代碼由someone..please支票如何初始化ThreadLocal的第一位置

嘗試一次用一小段代碼縮小問題范圍,以了解根本原因

幾個建議。

  1. 嘗試分離邏輯上分開的任務。 例如 初始化驅動程序和數據提供程序是兩個單獨的任務。 您可以在單獨的類中創建dataprovider,並在任何測試中引用它。 默認情況下,將在當前測試類或其基類之一中查找數據提供者。如果要將數據提供者放在其他類中,則它必須是靜態方法,並在其所在位置指定類可以在dataProviderClass屬性中找到:

  2. 您的驅動程序實例可以是單獨的類,因為它們都是靜態的。 threadlocal的實例化應在聲明點。 值的設置應在線程中。 因此,將新的ThreadLocal移到聲明中。

    1. 選擇pretest或class取決於您計划如何並行運行測試。 如果計划在類的所有方法中使用相同的驅動程序實例,則應使用beforeclass。 如果您打算將測試作為xml中的testtags並行運行,則應使用beforetest。
      由於您使用的是parallel =類,因此選擇beforeclass似乎是正確的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM