【问题标题】:Selenium multi browser execution with @DataProvider returns NullPointerException使用 @DataProvider 执行 Selenium 多浏览器返回 NullPointerException
【发布时间】:2018-07-05 21:19:01
【问题描述】:

我在 Selenium on Java 和 TestNg 项目中使用 @dataprovider,特别是在实现 saucelabs 所需功能的 TestBase 类上。 我担心的是此代码返回“NullPointerException”错误,因为从未采用数据提供者值。 有人能指出我的代码有什么问题吗(使用与示例中相同的代码:https://github.com/saucelabs-sample-test-frameworks/Java-TestNG-Selenium/blob/master/src/test/java/com/yourcompany/Tests/TestBase.java

public class TestBase {

protected WebDriver driver;
protected static String baseUrl;
protected Application app;
protected ConfigFileReader configRead;
protected PropertyLoader propertyRead;
public Logger Log = Logger.getLogger(BasicTest_Local.class.getName());

public static final String SAUCE_ACCESS_KEY = System.getenv("SAUCE_ACCESS_KEY");
public static final String SAUCE_USERNAME = System.getenv("SAUCE_USERNAME");

private ThreadLocal<WebDriver> webDriver = new ThreadLocal<WebDriver>();



    @DataProvider(name = "hardCodedBrowsers", parallel = true)
     public static Object[][] sauceBrowserDataProvider(Method testMethod) {
            return new Object[][]{              
            new Object[]{"firefox", "55.0", "Windows 10"},                
            new Object[]{"chrome", "65.0", "Windows 10"},                
    };}


    public void createDriver(String browser, String version, String os, String methodName)
        throws Exception, MalformedURLException, UnexpectedException {
        Class<? extends TestBase> SLclass = this.getClass();

        DesiredCapabilities capabilities = new DesiredCapabilities();

        // set desired capabilities to launch appropriate browser on Sauce
        capabilities.setCapability(CapabilityType.BROWSER_NAME, browser);
        capabilities.setCapability(CapabilityType.VERSION, version);
        capabilities.setCapability(CapabilityType.PLATFORM_NAME, os);
        System.out.println(CapabilityType.PLATFORM_NAME + CapabilityType.VERSION + CapabilityType.PLATFORM_NAME);

        capabilities.setCapability("seleniumVersion", "3.8.1");
        capabilities.setCapability("name", SLclass.getSimpleName());
        capabilities.setCapability("screenResolution", "1920x1080");

    this.webDriver.set(new RemoteWebDriver(new URL("http://" + SAUCE_USERNAME + ":" + SAUCE_ACCESS_KEY + "@ondemand.saucelabs.com:80/wd/hub"), capabilities));

    configRead = new ConfigFileReader();

    propertyRead = new PropertyLoader();

    baseUrl = propertyRead.getProperty("site.url");

    app = new Application(driver);
    getURL();

    }





private void getURL () {

    driver.get(baseUrl);
    driver.manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
    Log.info("Open a site URL");

}



@AfterMethod(description = "Throw the test execution results into saucelabs")
public void afterMethod(ITestResult result) throws Exception {

    ((JavascriptExecutor) driver).executeScript("sauce:job-result=" + (result.isSuccess() ? "passed" : "failed"));
    driver.quit();
}

}

仅供参考:我尝试在“createDriver”方法之前添加带有数据提供者名称的@Test 注释:

@Test(dataprovider="name") public void createDriver(String browser, String version, String os, String methodName)

但这种方法只打开浏览器和站点 url(baseURL),但从不去扩展 TestBase 类的测试类(“Login”):

  public class Login_and_CreateOrder extends TestBase {

  @Test (groups = {"HappyPath"})
  public void Login() {

    app.homePage().homePageDisplayed();
    Log.info("Validate Home Page");

    app.loginPage().Login_as( 
    configRead.getUserName2(),configRead.getPassword());
    Log.info("Login as user");

    assertTrue(app.loginPage().welcomeMessage.getText().contains("Hello"), 
    "Validate user's login.Display Welcome message");

    }
}

附加 .xml 文件

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

<suite name="Tests Suite" verbose="2" parallel="methods" thread-count="2">

<test name="SmokeRunTests" parallel="methods" thread-count="2">
    <classes>
           <class name="com.****.tests.Login"/>
       </classes>
   </test>

错误:

[ERROR] Tests run: 2, Failures: 2, Errors: 0, Skipped: 0, Time elapsed: 4.448 
s <<< FAILURE! - in TestSuite
[ERROR] Login(com.****.tests.Login)  Time elapsed: 0.365 s  <<< FAILURE!
java.lang.NullPointerException
at com.****.tests.Login.Login(Login.java:13)

[ERROR] afterMethod(com.****.tests.Login)  Time elapsed: 0.455 s  <<< 
FAILURE!
java.lang.NullPointerException

[INFO] 
[INFO] Results:
[INFO] 
[ERROR] Failures: 
[ERROR]   Login.Login:13 NullPointer
[ERROR]   Login.TestBase.afterMethod:95 » NullPointer
[INFO] 
[ERROR] Tests run: 2, Failures: 2, Errors: 0, Skipped: 0
[INFO] 
[INFO] ---------------------------------------------------------------------- 
--
[INFO] BUILD FAILURE
[INFO] -------------------------------------

【问题讨论】:

    标签: java selenium testng dataprovider saucelabs


    【解决方案1】:

    您的 DataProvider 有一个额外的逗号,

    @DataProvider(name = "hardCodedBrowsers", parallel = true)
     public static Object[][] sauceBrowserDataProvider(Method testMethod) {
            return new Object[][]{              
            new Object[]{"firefox", "55.0", "Windows 10"},                
            new Object[]{"chrome", "65.0", "Windows 10"}, //no need of comma for the last value           
    };}
    

    试试这个,我已经删除了那个逗号,它正在工作

     @DataProvider(name = "hardCodedBrowsers", parallel = true)
     public static Object[][] sauceBrowserDataProvider(Method testMethod) {
            return new Object[][]{              
            {"firefox", "55.0", "Windows 10"},                
            {"chrome", "65.0", "Windows 10"}                
    };}
    

    【讨论】:

    • 这些“testuser_1”、“Test@123”是什么意思?
    • 谢谢,但这没有帮助。我认为问题在于 DataProvider 名称从未传递给 createDriver 方法,因为没有 Test 注释。但在我的情况下,我不需要 TestBase 类中的 Test 方法,因为它不允许运行 Login Test 类。
    【解决方案2】:

    只需编辑 @Test 注释的值:

    @Test (groups = {"HappyPath"}, dataProvider = "hardCodedBrowsers")//you should add data provider
    public void Login(String browser, String version, String os, Method method) {
    //and add initialization for some browser
        this.createDriver(browser, version, os, method.getName());// you missed this init
        app.homePage().homePageDisplayed();
        Log.info("Validate Home Page");
    
        app.loginPage().Login_as( 
        configRead.getUserName2(),configRead.getPassword());
        Log.info("Login as user");
    
        assertTrue(app.loginPage().welcomeMessage.getText().contains("Hello"), 
        "Validate user's login.Display Welcome message");
    
        }
    

    【讨论】:

    • "this.createDriver(browser, version, os, method.getName());// 你错过了这个初始化”——我没有错过。浏览器初始化应仅位于基本测试内部(而不是主要测试内部)
    • 根据您提供的示例存储库,init 应该直接在测试中 - 而不是在基础测试中。见前。 github.com/saucelabs-sample-test-frameworks/…
    • 感谢您的示例,但您可以看到示例中的测试方法位于 dataprovider 所在的同一类中。就我而言,这将是一个基本类。但我有 1.Basic 类(其中浏览器和 url 被初始化)和一个主类,如 Login。这就是为什么我在初始化设置方法时遇到问题的原因。
    • 我不能同意你的看法。示例上的测试方法位于FollowLinkTest 类中,数据提供者位于TestBase 类中。请尝试我的解决方案并检查
    • Sergiy,在这种情况下,所有测试都将在远程saucelabs服务上执行,如果在本地运行则会失败
    猜你喜欢
    • 2021-09-21
    • 2018-06-06
    • 1970-01-01
    • 2011-11-10
    • 2012-04-30
    • 2016-08-16
    • 2019-10-12
    • 2012-08-29
    • 2016-12-09
    相关资源
    最近更新 更多