使用Selenium WebDriver,Selenium Grid和testNG运行并行测试

时间:2016-01-20 04:50:16

标签: java selenium testng remotewebdriver selenium-grid2

这是我在SO的第一篇文章;我是新手Selenium用户,具有Java初学者技能。

为您提供我们工作的背景;我们正在使用页面对象模型。我们所有的测试都使用一个 DataProvider 方法,该方法从" .xlsx"中提取数据。基于调用/使用DataProvider的测试用例名称的文件。

我们不确定是否已按照应有的方式宣布我们的 ThreadLocal 。而且,我们不确定 getDriver()方法的声明是否正确。另一个问题是我们不确定是否应该使用 &#34; @ BeforeTest&#34; /&#34; @ AfterTest&#34; < em>&#34; @ BeforeClass&#34; /&#34; @ AfterClass&#34; 在我们的设置 tearDown 方法上。

遇到以下问题:

  1. 一次测试失败,后续测试也失败。
  2. 有时候提取的测试数据不准确(抛出的列数据多于预期)。

  3. 以下是我们的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...");
            }
    
        }
    }
    


    这是我们的套件文件; &#39;横幅&#39;参数用于在&#34; .xlsx&#34;上查找特定表格。文件:

    <?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>
    


    关于我们如何使其发挥作用的任何建议?

3 个答案:

答案 0 :(得分:2)

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;
    }
}

答案 1 :(得分:0)

一次一件事......我相信你已被某人移交过这段代码。请先查看如何初始化threadlocal here

尝试使用一小段代码逐个缩小您的问题,以了解根本原因

答案 2 :(得分:0)

一些建议。

  1. 尝试分离您在逻辑上分离任务的内容。例如。初始化驱动程序和数据提供程序是两个单独的任务。您可以在单独的类中创建数据提供者,并在任何测试中引用它,例如。 “By default, the data provider will be looked for in the current test class or one of its base classes. If you want to put your data provider in a different class, it needs to be a static method and you specify the class where it can be found in the dataProviderClass attribute:

  2. 您的驱动程序实例化可以是一个单独的类,因为它都是静态的。 threadlocal的实例化应该在声明点。值的设置应该在线程中。因此,将新的ThreadLocal移动到您的声明中。

    1. 前测或课程的选择取决于您计划如何平行运行测试。如果计划在类的所有方法中使用相同的驱动程序实例,则应使用beforeclass。如果你打算在xml中并行地运行test作为testtags,那么应该使用beforetest 由于您使用的是parallel = classes,因此选择beforeclass似乎是正确的。