1
votes

I am running ThreadLocal tests on a single machine. I use code in @BeforeMethod to initiate the webpage. I have also tried writing this separately as a method in my Base Test class, and calling it in @BeforeMethod.

Everything seems to work fine, except the wrong users are being logged in with the wrong tests. This is strange because the Login method is not in the BaseTest class, it is called from the Page Object (And it works fine, besides logging in the wrong user for the test).

In this example, I have included the problem code in the @BeforeMethod, and also commented out the separate "initialize" method and method call, so you can see both ways I have tried it.

public class StackExample {

protected String baseURL;
public String browser;
private static ThreadLocal<WebDriver> threadedDriver = new ThreadLocal<WebDriver>();

@BeforeMethod(alwaysRun = true)
@Parameters({ "browser", "loginType" })
public void setup(String browser, String loginType, Method caller)
        throws MalformedURLException, InterruptedException {
    WebDriver driver = null;

    // Browsers
    if (browser.equalsIgnoreCase("Internet Explorer")) {
        System.setProperty("webdriver.ie.driver", "C:\\Users\\automation\\Selenium\\IEDriverServer.exe");
        driver = new InternetExplorerDriver();
    } else if (browser.equalsIgnoreCase("Firefox")) {
        System.setProperty("webdriver.gecko.driver", "C:\\Users\\automation\\Selenium\\geckodriver.exe");
        ProfilesIni firProfiles = new ProfilesIni();
        FirefoxProfile wbdrverprofile = firProfiles.getProfile("Webdriver2");
        driver = new FirefoxDriver(wbdrverprofile);
    } else if (browser.equalsIgnoreCase("chrome")) {
        System.setProperty("webdriver.chrome.driver", "C:\\Users\\automation\\Selenium\\chromedriver.exe");
        driver = new ChromeDriver();
    } else if (browser.equalsIgnoreCase("MicrosoftEdge")) {
        System.setProperty("webdriver.edge.driver", "C:\\Users\\automation\\Selenium\\MicrosoftWebDriver.exe");
        driver = new EdgeDriver();
    }

    setWebDriver(driver);
    this.browser = browser;
    System.out.println(browser);
    // initialize(loginType);
    System.out.println(loginType);

    if (loginType.equalsIgnoreCase("client"))
        ClientReportFactory
                .getTest(StringUtils.join("Client Test"), ' ') + " ("
                        + browser + ")", "This test is located in class: " + getClass().getName());
    else if (loginType.equalsIgnoreCase("advisor"))
        AdvisorReportFactory
                .getTest(StringUtils.join("Advisor Test"), ' ') + " ("
                        + browser + ")", "This test is located in class: " + getClass().getName());

    if (loginType.equalsIgnoreCase("client"))
        baseURL = "ClientWebsite.example";
    else if (loginType.equalsIgnoreCase("advisor"))
        baseURL = "AdvisorWebsite.example";
    else {
        System.out.println("Client or Advisor must be specified in TestNG XML");
    }
    driver.get(baseURL);
    driver.manage().window().maximize();

}

// public void initialize(String loginType) throws InterruptedException {
// if (loginType.equalsIgnoreCase("client"))
// baseURL = "ClientWebsite.example";
// else if (loginType.equalsIgnoreCase("advisor"))
// baseURL = "AdvisorWebsite.example";
// else{
// System.out.println("Client or Advisor must be specified in TestNG XML");
// }
// driver.get(baseURL);
// driver.manage().window().maximize();
//
// }

public static WebDriver getDriver() {
    return threadedDriver.get();
}

static void setWebDriver(WebDriver driver) {
    threadedDriver.set(driver);
}

@AfterMethod // (alwaysRun = true)
@Parameters({ "loginType" })
public void afterMethod(Method caller, String loginType) {
    // Here we are making sure we close the same test we opened.
    System.out.println(loginType);
    if (loginType.equalsIgnoreCase("client"))
        ClientReportFactory
                .closeTest(StringUtils.join("Client Test"), ' ') + " ("
                        + browser + ")");
    else if (loginType.equalsIgnoreCase("advisor"))
        AdvisorReportFactory
                .closeTest(StringUtils.join("Advisor Test"), ' ') + " ("
                        + browser + ")");
    getDriver().quit();
    threadedDriver.set(null);
}

@AfterSuite
@Parameters({ "loginType" })
public void afterSuite(String loginType) {

    if (loginType.equalsIgnoreCase("client"))
        ClientReportFactory.closeReport();
    else if (loginType.equalsIgnoreCase("advisor"))
        AdvisorReportFactory.closeReport();

    if (getDriver() != null) {
        getDriver().quit();
    } else {
        System.out.println("Drivers already closed");
    }
}
}

Here are my test methods. They call the actual SignIn method from their page objects. I know this isn't the problem because all other methods called from the page object are working fine with the correct test.

public class StackExampleTests extends StackExample {

@Test(enabled = true, priority = 0)
public void ClientTest1() throws Exception {
    ExtentTest t = ClientReportFactory.getTest();
    t.log(LogStatus.INFO, "Client 1 Login for " + browser);
    try {
        Login objLogin = new Login(getDriver());
        String username = "username1";
        String password = "password1";
        t.log(LogStatus.INFO, "Logging in as user: " + username);
        objLogin.SignIn(username, password);

        // perform First Client's tests here

    } catch (Exception e) {
        t.log(LogStatus.WARNING, "Exception found: " + e.getMessage().substring(0, 400)
                + t.addBase64ScreenShot(ClientReportFactory.CaptureScreen(getDriver())));
    }
}

@Test(enabled = true, priority = 1)
public void ClientTest2 throws Exception{
    ExtentTest t = ClientReportFactory.getTest();
    t.log(LogStatus.INFO, "Client 2 Login for " + browser);
    try {
        Login objLogin = new Login(getDriver());
        String username = "username2";
        String password = "password2";
        t.log(LogStatus.INFO, "Logging in as user: " + username);
        objLogin.SignIn(username, password);

        // perform Second Client's tests here

    } catch (Exception e) {
        t.log(LogStatus.WARNING, "Exception found: " + e.getMessage().substring(0, 400)
                + t.addBase64ScreenShot(ClientReportFactory.CaptureScreen(getDriver())));
    }
}
}

I think this trace means that it is starting all 3 of my tests in the same thread. But I'm not completely

Starting ChromeDriver 2.27.440174 (e97a722caafc2d3a8b807ee115bfb307f7d2cfd9) on port 44694
Only local connections are allowed.

Starting ChromeDriver 2.27.440174 (e97a722caafc2d3a8b807ee115bfb307f7d2cfd9) on port 12513
Only local connections are allowed.

Starting ChromeDriver 2.27.440174 (e97a722caafc2d3a8b807ee115bfb307f7d2cfd9) on port 32651
Only local connections are allowed.
1
Are you left with a bunch of extra browsers open when you try to run this after the tests complete? A quick glance leads me to believe the static driver is an issue, but I can't remember how testNG puts everything together under the hoodmrfreester
No, as it is now, the tests complete and close successfully. Just with the wrong login. And for some tests, the login doesn't matter, such as just checking the header links. Those all pass fine. But it seems like the logins get randomly switched around so for accounts with specific data, tests fail. It could be that any method called is just being randomly assigned to a test.dsidler
Another weird thing is that I modified this code from a Threadlocal<RemoteWebdriver> setup on Selenium Grid. And with RemoteWebDriver everything ran fine and this never happened. It's only on a local machine it gets confused.dsidler
What happens if you change ThreadLocal<WebDriver> threadedDriver, getDriver(), and setDriver() to not static? Or is that too painful of a change based on your architecture?mrfreester
I had tried making getDriver() and setDriver() to not static, with the same results. But not ThreadLocal<WebDriver>. I am now seeing the 3 tests started in different threads I think. Doing some tests but you may have solved my 2 day headache.dsidler

1 Answers

1
votes

It looks like your tests are having a driver identity crisis with which WebDriver belongs to them when running in parallel locally.

Setting ThreadLocal<WebDriver> threadedDriver, getDriver(), and setDriver() to not static should fix the problem.