2016-12-09 16 views
0

これは、ThreadLocal RemoteWebDriverを初期化する正しい方法ですか?パラレル実行に非静的WebDriverを使用する - Selenium - TestNG - Java

静的なWebDriverを持ってはいけないと言う人がいる記事を見ましたが、静的修飾子を削除するとNULLポインタ例外が発生します。

大部分はすべて正常に動作していますが、あるスレッドが別のスレッドでデータを入力することがあるという問題が発生しています。私はこれにつながる問題を解決しようとしています。

TestSetupクラス:

public class TestSetup { 

    private static ThreadLocal<RemoteWebDriver> threadDriver;// = new ThreadLocal<RemoteWebDriver>(); 

    @Parameters({"browserParam"}) 
    @BeforeClass(alwaysRun = true) 
    public void beforeClass(@Optional("") final String browserParam) throws InterruptedException, MalformedURLException { 

     // Set Driver 
     threadDriver = new ThreadLocal<RemoteWebDriver>() 
     { 

      @Override 
      protected RemoteWebDriver initialValue() 
      { 

       String browser = "Chrome"; 
       DesiredCapabilities dc = new DesiredCapabilities(); 

       if (browser.equals("Chrome")) 
       { 

        String chromeDriver = "C:\\workspace\\drivers\\chromedriver.exe"; 
        System.setProperty("webdriver.chrome.driver", chromeDriver); 

        // Access Grid Hub 
        dc.setBrowserName(DesiredCapabilities.chrome().getBrowserName()); 

       } // end Chrome 

       // Set the driver 
       try { 
        threadDriver.set(new RemoteWebDriver(new URL(hubURL), dc)); 
       } catch (MalformedURLException e) { 
        e.printStackTrace(); 
       } 

       return getDriver(); 

      } // end initialValue 

     } // end threadDriver 

    } // end beforeClass 



    @AfterClass(alwaysRun = true) 
    public void afterClass() { 

     // Quit the Webdriver 
     getDriver().quit(); 

    } // end afterClass 



    public RemoteWebDriver getDriver() { 

     return threadDriver.get(); 

    } // end getDriver 

} // end TestSetup class 

LoginTestクラス:それはTestSetupクラスの静的でない場合

private Function perform = new Function(); 

@Test (retryAnalyzer = Retry.class, groups={"baseline", "negative"}) 
public synchronized void loginEmptyUsername() throws InterruptedException { 

ExtentTest test = ExtentTestManager.getTest(); 

// Go to Secure 
getDriver().get(StoredVariables.getsecureSite().get()); 

// Wait for password 
perform.waitForElementToBeClickable(SLogin.password_txtbx(), "id"); 

// Clear email field 
SLogin.email_txtbx(getDriver()).clear(); 

// enter password 
SLogin.password_txtbx(getDriver()).clear(); 
SLogin.password_txtbx(getDriver()).sendKeys(StoredVariables.getpassword().get()); 

// click Sign In 
SLogin.signIn_btn(getDriver()).click(); 

// Wait for error 
perform.waitForElementToBeClickable(SLogin.loginError_txt(), "id"); 

// Verify error text 
Assert.assertTrue(SLogin.loginError_txt(getDriver()).getText().contains("Oops! Your email or password (case sensitive) was incorrect. Please try again.")); 

// Log test 
test.log(LogStatus.INFO, "login", "Tried logging in with an empty email"); 

} // end loginEmptyUsername 

がどのようにテストクラスにwebdriverをを渡すでしょうか?

UPDATEは:

(少なくとも現時点では)私の問題を解決した私の最初の実装を使用したが、5つのインスタンスの最大を利用とは対照的に、唯一の3つのインスタンスを許可するようにノードを制限することが表示されます。

答えて

0

メソッド内からThreadLocalを初期化するべきではありません。実装は、@BeforeClassメソッドを介して渡されるブラウザのフレーバに依存します。このメソッドは、initialValue()実装によって消費され、ThreadLocalをインスタンス化してWebDriverインスタンスを永続化します。この問題は、次にスレッドがローカルのスレッドにget()経由で照会し、null値がある場合は、initialValue()にルーティングされますが、最後のブラウザのパラメータだけが記憶されるという問題があります。だからあなたのトータルな実装はトスに向かいます。

私はこの動作を説明するブログ記事を書いています。それを見てくださいhere

同じスレッドを実行することを保証する場合、TestNGは@BeforeMethod>@Test>@AfterMethodの組み合わせに対してのみこの保証を適用します。他のすべてについては、そのような保証はありません。

私はthisのブログを参照することもできます。ここで私は並列実行について話します。

これを実現するための正しい方法は、以下のようにする必要があります:

public class TestSetup { 

    private String browserFlavor; 

    private static final ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<RemoteWebDriver>() { 
     @Override 
     protected RemoteWebDriver initialValue() { 
      //By default lets set the browser flavor always as Chrome. 
      return new ChromeDriver(); 
     } 
    }; 

    @Parameters ({"browserParam"}) 
    @BeforeClass (alwaysRun = true) 
    public void beforeClass(@Optional ("") final String browserParam) { 
     this.browserFlavor = browserParam; 
    } 

    @BeforeMethod 
    public void instantiateBrowser() { 
     switch (browserFlavor) { 
      case "firefox": 
       driver.set(new FirefoxDriver()); 
       break; 
      case "ie": 
       driver.set(new InternetExplorerDriver()); 
       break; 
     } 
    } 

    @Test 
    public void testMethod() { 
     driver.get().get("http://www.google.com"); 
    } 

} 
+0

私はあなたのソリューションを実現します(ただしRemoteWebDriverで)まだ、このため、別のスレッドにデータを入力する一つのスレッドの問題に実行している原因となっていますこれらのスレッドはいずれも期待されるデータを含んでいないために失敗します。 –

+0

また、この設定では、test.xmlファイルに11個のクラスがあり、xmlファイルにはthread-count = "2"と表示され、最初の2つのクラスは正常に実行されますが、残りは実行されませんそれはセッションIDがヌルであると言います –

+0

@ダストインN。本物のソリューションについては、このブログの投稿https://rationaleemotions.wordpress.com/2013/07/31/parallel-webdriver-executions-using-testng/をご覧ください。あなたが何をしているのかを見ずに何が間違っているのかを言う。しかし、私が共有した解決策によって、Webdriverのインスタンスがスレッド間でリークすることはありません。 –

関連する問題