Q:

Parallel TestNG tests with ExtentReports are using the wrong @BeforeMethod

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.

A:

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.

