static Webdriver instance synchronization in java - java

GlobalVariables class holds different variables which are used across my framework one of them is WebDriver instance:
public class GlobalVariables
{
public static WebDriver driver;
//Some other static global variables required across my framework
public GlobalVariables(String propertiesFile)
{
initializeVariables(propertiesFile);
}
public void initializeVariables(String propertiesFile)
{
GlobalInitializer obj=new GlobalInitializer();
obj.initialize(String propertiesFile);
}
}
GlobalInitializer contains methods to initialize all the GlobalVariables:
public class GlobalInitializer extends GlobalVariables
{
public void initialize(String propertiesFile)
{
//Some logic to read properties file and based on the properties set in it, call other initialization methods to set the global variables.
}
public void initializeDriverInstance(String Browser)
{
driver=new FireFoxDriver();
}
//Some other methods to initialize other global variables.
}
I have many GetElement classes which use the driver instance to get UI control elements E.g:
public class GetLabelElement extends GlobaleVariables
{
public static WebElement getLabel(String someID)
{
return driver.findElement(By.id(someId));
}
//Similar methods to get other types of label elements.
}
public class GetTextBoxElement extends GlobaleVariables
{
public static WebElement getTextBox(String someXpath)
{
return driver.findElement(By.xpath(someXpath));
}
//Similar methods to get other types of text box elements.
}
I have other classes which perform some actions on the UI Control(This classes too use the global variables) E.g:
public class GetLabelProperties extends GlobalVariables
{
public static String getLabelText(WebElement element)
{
return element.getText();
}
}
public class PerformAction extends GlobalVariables
{
public static void setText(String textBoxName,String someText)
{
driver.findElement(someLocator(textBoxName)).setText("someText");
}
//Some other methods which may or may not use the global variables to perform some action
}
My test class in testng looks like this:
public class TestClass
{
GlobalVariables globalObj=new GlobalVariables(String propertiesFile);
#Test(priority=0)
{
GlobalVariables.driver.get(someURL);
//Some assertion.
}
#Test(priority=1)
{
WebElement element=GetLabelElement.getLabel(someID);
String labelName=GetLabelProperties.getLabelText(element);
//Some assertion.
}
#Test(priority=2)
{
WebElement element=GetTextBoxElement.getTextBox(someXpath);
PerformAction.setText(element.getText(),someText);
//Some assertion.
}
}
I have similar multiple test classes based on scenarios.
Now this tests are running fine if i am running them individually. But when i try to run them in parallel, then this tests are failing in some weird fashion. On analyzing i found out that its the static global variables which are getting initialized by each tests thus leaving the other tests to fail. Now how should i go about achieving my objective to run multiple tests parallely with minimal changes in my framework design? i have tried searching for options, and i have come across some option i.e 1) use of synchronized. 2) Create ThreadLocal instance(Note : I have tried this solution but still same issue. tests are mixing up with each other resulting in failure. I had marked the WebDriver instance as ThreadLocal and overriden the initialValue method of ThreadLocal to initialize the driver instance. Still i am not sure whether i had implemented it correctly or not.). Now i am not sure how best to implement any one of this solution in the given scenario. Any help is appreciated. TIA!

I have found out the solution : Use of ThreadLocal is the best solution to run tests in a huge multithreaded environment.
Code snippet to use WebDriver in multithreaded environment:
public static ThreadLocal<WebDriver> driver;
driver=new ThreadLocal<WebDriver>()
{
#Override
protected WebDriver initialValue()
{
return new FirefoxDriver(); //You can use other driver based on your requirement.
}
};
Now every time a test thread is created a new browser will open. ThreadLocal will make sure that there's only one copy of static webdriver instance per thread. [NOTE: Make sure your other global variables are too ThreadLocals. In my case they were not thats why i was running into test goof up issue]. Some extra knowledge which i would like to share so that others may find it informative. In ThreadLocal whenever the ThreadLocal.get() method is called you have to make sure that there is a provision to initialize the thread local as shown above in initialValue() method or you may run into null pointer exception. Thanks everyone.

If you are going to run non-parallel, then using a static webdriver member (or a instance shared between test classes by passing by reference) is fine because it is a good way to not have to close the webdriver instance between test classes. If you want to run parallel though, you need to have one instance of webdriver for EACH thread and so in that case using a static member is the WRONG way to go. Instead you need to create or pass a webdriver instance when the test case class is invoked.
Also, you are breaking a test into separate tests for each step of the test. That is very unusual and I do not see the reason why you are doing that. You could really simplify your tests by keeping all the test steps within one singe test case like people usually do.

You are getting this because of how JVM handles static members and methods.
You can't have a static webdriver object if you are going to run in parallel.
Source: The automated regression system i implemented where I work - we had this issue.

you can try something like this
public class DriverManager {
private static final ThreadLocal<WebDriver> threadLocal = new ThreadLocal<WebDriver>();
public static WebDriver getDriver() {
return threadLocal.get();
}
public static void setDriver(WebDriver driver) {
threadLocal.set(driver);
}
public static void closeDriver() {
if (getDriver() != null) {
try {
getDriver().close();
} catch (Exception e) {
e.printStackTrace();
}
try {
getDriver().quit();
} catch (Exception e) {
e.printStackTrace();
}
}
threadLocal.remove();
}
}

Related

How to send variable between classes while multithreading

This a much simplified version of my multithreading project and its just a way to replicate the issue in a simpler way for easy understanding.
So I have two classes startSession.java and main.java
what I am trying to do is to send a variable from startSession.java to main.java and Im also using multithreading. However, the problem I am facing is that everytime I try to retrieve the variable inside main I get a null value.
Inside startSession theres the run method and Setter(setSessionKey(String sess)) and getter(getSessionKey()) methods. I hardcoded a variable to test.
The get method only works inside the run method but when I call getSessionKey() from inside main I get a null as seen below. However, this is only a problem when I am using multithreading. When I dont use multithreading and instead just call the run method from inside main, the variable Im looking for is no longer null.
My question is there a way to send a variable from startSession to main while using multithreading ?
thank you
startSession.java
public class startSession extends Thread {
static String sessionKey;
public void run() {
String createdSession = "83248329";
setSessionKey(createdSession);
System.out.println("Inside run method: " + getSessionKey());
}
public String getSessionKey() {
return sessionKey;
}
public void setSessionKey(String sess) {
sessionKey = sess;
}
}
main.java
package com.Server;
public class Main {
static String session;
public static void main(String[] args) throws InterruptedException {
startSession startSession = new startSession();
startSession.start();
session = startSession.getSessionKey();
System.out.println("Inside Main: " + session);
}
}
with multithreading
without multithreading
Use a BlockingQueue whereby the Thread (Producer) will add to the shared queue and the Main (Consumer) will block on the take
main
public static void main(String[] args) throws Exception {
// example only uses 1024 - check what is best for you
BlockingQueue queue = new ArrayBlockingQueue(1024);
StartSession producer = new StartSession(queue);
....
System.out.println(queue.take());
startSession
String createdSession= "83248329";
queue.add(createdSession);
see https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/BlockingQueue.html
and
https://jenkov.com/tutorials/java-util-concurrent/blockingqueue.html

How to embed every test in a wrapper logic?

Given the requirement that every junit test have to run in the following wrapper:
#Test
public void testFooBar() {
SpecialLogic.runWith(new SpecialLogic("blah", "foo", ANYTHING), () -> {
// my test
});
}
I am trying to avoid adding SpecialLogic.runWith(...) for each test.
Is there any possibility by using #BeforeEach or any other way?
Otherwise, there is much of duplicated code:
#Test
public void testFooBar_2() {
SpecialLogic.runWith(new SpecialLogic("blah", "foo", ANYTHING), () -> {
// my test logic 2
});
}
#Test
public void testFooBar_3() {
SpecialLogic.runWith(new SpecialLogic("blah", "foo", ANYTHING), () -> {
// my test logic 3
});
}
There are two ways of doing this:
Write your custom Runner, all the tests will have to run with this runner.
This may be inappropriate if you already use another runner (say for spring or mockito)
Write your own Rule. The rule is a little bit newer way of doing what you've asked for,
and it doesn't "occupy" the slot of a runner which can be only one.
public final class SampleRule implements TestRule {
#Override public Statement apply(final Statement base,
final Description description) {
return new Statement() {
#Override public void evaluate() throws Throwable {
// do your stuff before actually running the test
try {
base.evaluate(); // This line actually runs the test.
} finally {
// do your stuff after running a test
}
}
};}}
Here is one of numerous guides for writing Rules:
Looks like you should implement your own TestRunner to wrap your custom logic around each test method call. There is an article over at Baelung explaining how this works.
#Before and #After? It won't use closures but should be functionally the same.
https://junit.org/junit4/javadoc/latest/org/junit/Before.html
https://junit.org/junit4/javadoc/latest/org/junit/After.html

Java Selenium close browser after assertTrue

I have a code with many classes.
There is a class which creates the driver -
public class DriverDelegate {
private String baseURL = "someLink";
private WebDriver driver;
private WebDriverWait wait;
DriverDelegate(String url) {
System.setProperty("webdriver.chrome.driver", "${directory}");
driver = new ChromeDriver();
driver.get(baseURL + url);
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
wait = new WebDriverWait(driver, 5);
}
public WebDriver getDriver() {
return driver;
}
I create new driver for every test. And most of my lines are the ones containing assertTrue like this-
public class UserInterfaceTests extends BaseTest{
#Test
public void headerClicker() throws java.lang.Exception {
//Startup
DriverDelegate driverDelegate = new DriverDelegate("url");
WebDriver driver = driverDelegate.getDriver();
//Some random assertTrue
assertTrue("Test(HeaderClicker) - NoSuchElementException click", TestHelper.headerClicker(schedule, driver));
//I hope that it is not neccessary to put up all helper classes like TestHelper or BaseTest
Now I launch my tests from a class called Startup -
public class Startup{
#Test
public void HeaderClicker() throws Exception{ UserInterfaceTests UI = new UserInterfaceTests(); UI.headerClicker();}
My question here is how to close the browser after the assertTrue fails. Things like #AfterTest, #AfterSuite etc do not work because other methods can not use the same driver that was used in the test.
Any ideas?
Ok there are a few things I want to touch on here. First off, #shutdown -h now is correct in their comment that you shouldn't be programmatically creating test classes and running their #Test methods yourself. Let the test running framework handle that (e.g. TestNG, JUnit, etc).
To the point of your actual question, though, is that you want pre-test and post-test methods to handle behavior that occurs before and / or after your actual test method. For these to work, though, you need to let the test framework handle the running of the tests. You mentioned #AfterTest and #AfterSuite as not being correct for your use case, though not for the reason you specified (entirely). #AfterTest in TestNG only is executed once after all the test methods in all the classes inside of a <test> node specified in a suite. #AfterSuite is only executed once after all the test methods in the entire suite. What you are looking for is the #AfterMethod annotation.
Example:
public class FooTest {
private DriverDelegate driver;
#BeforeMethod
public void setup() {
try {
driver = new DriverDelegate("url");
} catch (Exception ignore) { }
}
#AfterMethod
public void tearDown() {
try {
driver.quit();
} catch (Exception ignore) { }
driver = null;
}
#Test
public void foo() {
// do test stuff
}
}
In the above code, when TestNG runs this test class, each method annotated with #Test in this class will have a corresponding #BeforeMethod execution that initializes the driver and an #AfterMethod that closes the driver even if the test fails. Couple of points to make about this type of setup with TestNG:
(1) TestNG does not create separate instances of the test class so if you save state on the class object then you cannot run the test methods themselves in parallel within a class since you would have multiple methods trying to create new drivers and save them to the same variable, corrupting the state of the other tests that are running. You can run with parallel mode of per class (e.g. have 5 threads, each running a separate test class at the same time).
(2) Why did I wrap the #BeforeMethod and #AfterMethod bodies in a try-catch block? Because TestNG takes a fail quickly on configuration method exceptions and can cause other tests that haven't run yet to be skipped so you need to deal with any code that could possibly fail. By wrapping the creating and closing of the web driver you can ignore the error and continue on running other tests. If the driver fails to be created, for instance, the driver variable will be null and that #Test method will fail but others might succeed. Ideally, you should probably have some logging of the exception so that you can investigate why the driver failed to be created, for instance.
Also, if you need to use a driver in many test classes, you can make a base class that does the creation of the driver along with the closing of it after each method and have your test classes extend that. If you have a class with a method annotated with #Test on it, it will run any #BeforeMethod methods on that test class AND on all of the super classes as well. There is guaranteed ordering of the methods between classes (though not if you have multiple #BeforeMethod methods in the same class).
public abstract class A {
#BeforeMethod
public void setupA() { }
}
public class B extends A {
#BeforeMethod
public void setupB() { }
#Test
public void foo() { }
}
In the above, when foo is run, it will have run first setupA and then setupB. After methods work in the same way, but in the reverse order.

Integration test before others

I have a bunch of integration tests that need to have a database populated before running. This task takes about 30 minutes, so it is not feasible to run it before every test.
I'm using junit and I'd like to be able to annotate this one class with something so that it runs and completes before the others start. Is this possible?
(most of the annotations I found only work on methods, e.g. #Rule)
I've done this in the past by adding setup and teardown functions to the individual test classes, annotated with #BeforeClass and #AfterClass.
#BeforeClass
public static void setupBeforeClass() {
DatabasePopulater.populate();
}
#AfterClass
public static void tearDownAfterClass() {
DatabasePopulater.dePopulate();
}
If more than one test class requires the same setup to be done, the setup function can do a kind of reference counting to make sure they only do their work the first time it's called:
public class DatabasePopulater {
AtomicInteger invocations = new AtomicInteger();
....
public static void populate() {
if (0 == ivocations.getAndIncrement()) {
// Actually populate DB
}
}
public static void dePopulate() {
if (0 == ivocations.decrementAndGet()) {
// Actually clear DB
}
}
If you are using something like ant/gradle to execute the test suite, you could separate out the db population into a standalone java program and then have a depends="populateDB" on the junit task.

How to run tearDown type method for a specific test in JUnit class with multiple tests?

I have a junit testCase class with multiple test methods in it ( As requirement , we don't want to create separate class for each test.)
I wanna create a tearDown type method for EACH test method , which will run specifically for that test. Not for ALL test.
My problem is , in many tests i Insert record in database, test it and delete it after test.
But, If a test fails mid way , control don't reaches till end my dummy record ain't deleting.
I think only ONE tearDown() is allowed for one class, and this tearDown() don't know what object/record i created or inserted and what to delete!!!
I want to create a tearDown() or #After method just for one specific test. Something like finally{} in java for each method.
For Eg:
public class TestDummy extends TestCase {
public void testSample1(){
InsertSomeData1();
assertFalse(true);
runTearDown1();
}
public void testSample2(){
InsertSomeData2();
assertFalse(true);
runTearDown2();
}
public void runTearDown1(){
deleteDummyDatafromTestSample1....
}
public void runTearDown2(){
deleteDummyDatafromTestSample2....
}
}
Here control will never go to runTearDown1() or runTearDown2() and I don't a one common tearDown() because it won't know what data I inserted and thats specific to each method.
It seems your test relies on a fixed database, and future tests will break if your current test breaks. What I'd recommend is not to focus on this particular problem (a test-specific tearDown method that runs for each test), but your main problem - borken tests. Before your test run, it should always work with a clean database, and this should be the case for each test. Right now, your first test has a relationship with the second (through the database).
What the right approach would be is that you recreate your database before each test, or at the very least reset it to a basic state. In this case, you'll want a test like this:
public class TestDummy {
// this code runs (once) when this test class is run.
#BeforeClass
public void setupDatabase() {
// code that creates the database schema
}
// this code runs after all tests in this class are run.
#AfterClass
public void teardownDatabase() {
// code that deletes your database, leaving no trace whatsoever.
}
// This code runs before each test case. Use it to, for example, purge the
// database and fill it with default data.
#Before
public void before() {
}
// You can use this method to delete all test data inserted by a test method too.
#After
public void after() {
}
// now for the tests themselves, we should be able to assume the database will
// always be in the correct state, independent from the previous or next test cases.
#Test
public void TestSample2() {
insertSomeData();
assertTrue(someData, isValid());
}
}
Disclaimer: JUnit 4 tests (using annotations), might not be the right annotations, might not even be the right answer(s).
You could have smth like this:
interface DBTest {
void setUpDB();
void test();
void tearDownDB();
}
class DBTestRunner {
void runTest(DBTest test) throws Exception {
test.setUpDB();
try {
test.test();
} finally {
test.tearDownDB();
}
}
}
public void test48() throws Exception {
new DBTestRunner().runTest(new DBTest() {
public void setUpDB() {...}
public void test() {...}
public void tearDownDB() {...}
});
}
#iluxa . Gr8.. Your solution is perfect!!! In one test class i created two tests test48 and test49 (same as required in my code above testSample1 and testSample2) and viola! every test method now gets its own setup() and tearDown. Only this solution looks little complicated as need to use DBTestRunner in each method, but I don't see any better solution. I was thinking Junit may have some direct solution. like #After or tearDown() with some parameter or something.
Tks a lot.
Use MethodRule:
public class MyRule implements MethodRule {
#Override
public Statement apply(final Statement base, FrameworkMethod method, Object target) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (AssertionError e) {
doFail();
} finally {
doAnyway();
}
}
};
}
}
Then declare it in your test class:
public class TestDummy{
public MethodRule rule = new MyRule();
......
}

Categories