Dataprovider Mixing Up Values for Parallel Methods - parallel-processing

I have two methods that use the same data provider. The Data provider reads an excel file to build the object to pass to the methods. However, when running the two methods in parallel, the data provider only passes back one variable for both methods.
I attempted to change the dataprovider variable names and object names but this did not work. I confirmed that the excel util function is working. Each if statement is called correctly in the data provider method, but it returns the wrong variable. How can I ensure that the data provider executes sequentially as to now mix up the variables?
Here is my Java class with testNG
public class dataprovidertest extends DriverMethods {
#Test (groups = {"test"}, dataProvider = "datadriven")
public void method1(String var1) throws Exception {
System.out.println("method 1 variable: " + var1);
}
#Test (groups = {"test"}, dataProvider = "datadriven")
public void method2(String var2) throws Exception {
System.out.println("method 2 variable: " + var2);
}
#DataProvider (name = "datadriven")
public Object[][] provideData(Method m) throws Exception{
if(m.getName().equalsIgnoreCase("method1")) {
String sTestCaseName1 = m.getName();
Object[][] testObjArray1 = ExcelUtils.getTableArray("C:\\Users\\user\\dataprovidertest_TestData.xlsx", sTestCaseName1);
return (testObjArray1);
}
if(m.getName().equalsIgnoreCase("method2")) {
String sTestCaseName2 = m.getName();
Object[][] testObjArray2 = ExcelUtils.getTableArray("C:\\Users\\user\\dataprovidertest_TestData.xlsx", sTestCaseName2);
return (testObjArray2);
}
return null;
}
Here is my xml file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="methods" >
<test thread-count="6" name="Test" parallel = "methods">
<classes>
<class name="cpq.dataprovidertest">
<methods>
<include name ="method1"/>
<include name ="method2"/>
</methods>
</class>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
Here is a description of my excel sheet:
Sheet "method1" has value "method1 var"
Sheet "method2" has value "method2 var"
Currently, the output is:
[testng] method 2 variable: method2 var
[testng] method 1 variable: method2 var
or
[testng] method 2 variable: method1 var
[testng] method 1 variable: method1 var
How can I change this so it becomes:
[testng] method 2 variable: method2 var
[testng] method 1 variable: method1 var
Thanks!
i noticed that when I separate the two methods into class tags in the xml file, and run the tests parallel by classes, it works as expected:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" data-provider-thread-count="2">
<test thread-count="6" name="Test" parallel = "classes">
<classes>
<class name="cpq.dataprovidertest">
<methods>
<include name ="method1"/>
</methods>
</class>
<class name="cpq.dataprovidertest">
<methods>
<include name ="method2"/>
</methods>
</class>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->

try with synchronized like
public synchronized Object[][]
Updated: add synchronized to method which collects data from sheet.

Related

Send parameters to injected mock beans

Doing a component test with testNG I need to mock a service that gets some external data.
To do this I configure the mock in the file spring-test-config.xml like this:
<beans xmlns=...>
<context:component-scan base-package="..." />
<bean id="dataRetrieverBean" class="org.my.project.DataRetrieverBeanMock" scope="prototype"/>
</beans>
And then I reference this config file in my test class like this:
#Test()
#ContextConfiguration(locations = { "classpath:spring-test-config.xml" })
public class MyNGTest extends AbstractTestNGSpringContextTests {
[...]
}
The mock always return "Hello world" when the component that I want to test calls "getStringResponse()" on it:
public class DataRetrieverBeanMock implements Response {
#Override
public String getStringResponse() {
return "Hello world";
}
}
Till here everything works as expected!
Now to test the component under different conditions I need that the String returned by DataRetrieverBeanMock (currently hardcoded with "Hello world") changes for each test case, for example the first test would test the component when the response is "success", the second when the response is "error 109" and so on.
How can I define the string to be returned inside the test case and pass it to the mock bean?

How does the # option operator work in AEM HTL templates

I spen a bit of time trying to read the official documentation on the AEM # operator and the official syntax specification, but I do not understand the logic behind.
Let's take this example presented in the documentation:
${myVar # optOne, optTwo=bar}
How will this expression be evaluated? What is the effect of the assignment optTwo=bar?.
Or this example in the syntax specification:
${myVar # optOne, optTwo=myVar, optThree='string', optFour=[myVar, 'string']}
How each assignment in the list (optTwo=myVar, optThree='string', optFour=[myVar, 'string']) will affect the final value to which the expression will be evaluated to?
In my project we are using this # operator to pass values to the Java backend logic. I have created a sample use-case to demonstrate the usage of the # operator.
I have created a simple info component with a textfield, a numberfield and a checkbox. The corresponding cq:dialog's .content.xml is as below -
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Info"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/tabs"
type="nav"/>
<items jcr:primaryType="nt:unstructured">
<tab
jcr:primaryType="nt:unstructured"
jcr:title="Properties"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<columns
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<name
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
class="field-whitespace"
fieldDescription="Enter full name of the user"
fieldLabel="Full Name"
name="./fullName"/>
<age
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/numberfield"
class="field-whitespace"
fieldDescription="Enter the age of the user"
fieldLabel="Age"
name="./age"/>
<married
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/checkbox"
class="field-whitespace"
fieldDescription="Check if the user is married"
name="./married"
text="Married?"
value="true"/>
</items>
</columns>
</items>
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
</tab>
</items>
</content>
</jcr:root>
The corresponding HTL file is as below -
<div data-sly-test="${wcmmode.edit || wcmmode.design}">
Info Component
</div>
<sly
data-sly-use.info="${'org.redquark.aem.learning.core.cq.text.InfoComponent' #
fullName=properties.fullName,
age=properties.age,
married=properties.married
}" />
<sly data-sly-test="${info}">
<h1>${info.details}</h1>
</sly>
Here, you can see that in the tag, we are passing values from the JCR in the variables fullName, age and married.
The java code that will read these values is as below -
package org.redquark.aem.learning.core.cq.text;
import com.adobe.cq.sightly.WCMUsePojo;
public class InfoComponent extends WCMUsePojo {
private String details;
#Override
public void activate() throws Exception {
String fullName = get("fullName", String.class);
Integer age = Integer.parseInt(get("age", String.class));
Boolean isMarried = Boolean.parseBoolean(get("married", String.class));
details = fullName + " is " + age + " years old and is " + (isMarried ? "married" : " not married");
}
/**
* #return the details
*/
public String getDetails() {
return details;
}
}
Or if you are using SlingModels instead of Java Use API then you can access those values in a typical Sling Model way.
package org.redquark.aem.learning.core.models.text;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
#Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class InfoModel {
#Inject
#Optional
#Default(values = "Test")
private String fullName;
#Inject
#Optional
#Default(values = "0")
private String age;
#Inject
#Optional
#Named("married")
#Default(values = "false")
private String isMarried;
// Variable that will be read in the HTL file
private String details;
#PostConstruct
protected void init() {
details = fullName + " is " + Integer.parseInt(age) + " years old and is "
+ (Boolean.parseBoolean(isMarried) ? "married" : " not married");
}
/**
* #return the details
*/
public String getDetails() {
return this.details;
}
}
Of course, then you have to call your InfoModel class in the HTL code as
<sly data-sly-use.info="${'org.redquark.aem.learning.core.models.text.InfoModel' #
fullName=properties.fullName,
age=properties.age,
married=properties.married
}" />
You see, here we are reading the same values which were passed in the HTL code. We can then perform any business logic on them.
I hope this helps. Cheers!

Properties not loading while using 2 context place holders

I wrote a test class to read properties defined
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath*:config/TestOne.xml","classpath*:config/TestTwo.xml"
})
public class PropertyTest {
#Value("${test.one:DEFAULT}")
private String test;
#Value("${test.two:DEFAULT}")
private String test2;
#Test
public void TestProperty(){
System.out.println(test + "," + test2);
}
}
TestOne.xml
<context:property-placeholder
location="classpath*:/config/testone.properties"
ignore-unresolvable="true" order="1" />
TestTwo.xml
<context:property-placeholder
location="classpath*:/config/testtwo.properties"
ignore-unresolvable="true" order="2" />
testone.properties
test.one=testone
testtwo.properties
test.one=testone
test.two=test
While running the Test, output is
testone,DEFAULT
it is not fetching test.two from property.
If I am not specifying the default value
#Value("${test.two}")
private String test2;
Output is
testone,test
Can anybody help?
I fear that this problem: "two property placeholder and a default value" is not easy to solve, because it looks like the default value is already "triggerd" by the first property-placeholder so the second one does not "need" to set this property "again".
A workarround is to have only one property-placeholder with two config files and the highes order:
<context:property-placeholder
locations="classpath*:/config/testone.properties,
classpath*:/config/testtwo.properties"
ignore-unresolvable="true" order="0" />
(attention: locations property instead of location)

Create class reflection if constructor argument is heir class

Question: How can I properly create class reflection, if class constructor contains heir class argument?
I have:
interface Car {}
class SportCar implement Car{}
class CarService {
public CarService(String str, Car car) {
...
}
}
But, when I try to do:
Class c = Class.forName("vbspring.model.CarService");
Class[] paramTypes = {String.class, SportCar.class};
Constructor constr = c.getDeclaredConstructor(paramTypes);
it throws: java.lang.NoSuchMethodException: vbspring.model.CarService.(java.lang.String, vbspring.model.SportCar)
P.S. My .xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="carService" class="model.CarService">
<constructor-arg value="Car Rental Service"/>
<constructor-arg ref="sportCar"/>
<property name="startCar"/>
</bean>
<bean id="sportCar" class="model.SportCar"/>
</beans>
EDIT: I try to write something like my own Spring Framework. I must create not only classes that belongs to Car hierarchy, so I try to write universal method that can create class of arbitrary type.
I can't write: Class[] paramTypes = {String.class, Car.class};
I must write something universal, like:
paramTypes[index++] = obj.getClass();
where obj - is SportCar or Car bean pulled from .xml by parser
The errors java.lang.NoSuchMethodException: vbspring.model.CarService.(java.lang.String, vbspring.model.SportCar) states you have no constructor like:
public CarService(String, SportCar)
which you don't. You have:
public CarService(String, Car) {
Change your code to
Class c = Class.forName("vbspring.model.CarService");
Class[] paramTypes = {String.class, Car.class}; // the constructor takes Car not SportsCar
Constructor constr = c.getDeclaredConstructor(paramTypes);
Then when you call the constructor to get a new instance, you can pass a SportsCar instance or any other Car instance for that matter.
constr.newInstance("sport", new SportsCar());
// or
constr.newInstance("a jeep", new Jeep());
// or
constr.newInstance("long car", new Limousine());
assuming Jeep and Limousine implement Car.

is there a way to use the same webdriver object for multiple java classes when running within a testng suite?

is there a way to use the same webdriver object for multiple tests/classes when run within a testng suite? What I mean is to start the WebDriver instance with one class, but continue using it over subsequent classes/tests in the suite?
The problem I am facing is that 10 differect classes have this statement:
WebDriver driver = new FirefoxDriver();
and it open 10 different instances even after I restrict TestNG with parallel mode set a s false. It really sucks up my system memory.
I wat a solution to use same WebDriver and run different classes over without having to multiple browser and Webdriver insntances.
Put all your classes in a <test> tag and initialize the driver in a #BeforeTest method which you store in the base class so that all your test methods can access it.
I'm not sure what it is in java but in c# you just instantiate the webdriver as a field
private WebDriver driver = new FirefoxDriver();
then just reference driver from that point on out
driver.findElements(By.TagName('h1'));
ISFW provides nice way to handle it. It will creates new instance if required otherwise utilize the same one. However you don't require to write code for setup and teardown. You need to set browser string in property file and it will manage for RC or webdriver for given browser string.
I have achieved this as following:
1: created a startup class
public class Start {
public static WebDriver wd;
#BeforeSuite
public void Setup() {
System.setProperty "webdriver.chrome.driver","D:\\chromedriver.exe");
wd = new ChromeDriver();
wd.manage().timeouts().implicitlyWait(30,TimeUnit.SECONDS);
wd.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
wd.manage().window().maximize();
wd.get("URL");}
}
2: reference the static driver instance in other classes by its class qualifier as
public void VerifyTitle() {
Assert.assertEquals(Start.wd.getTitle(), "Title", "Incorrect Title");}
3: add the class and the setup method in testing.xml file as
<suite name="QA">
<test name="1Class">
<classes>
<class name="just.Start">
<methods>
<include name="Setup"></include>
</methods>
</class>
<class name="just.LoginPage">
<methods>
<include name="VerifyTitle"></include>
</methods>
</class>
<class name="just.HomePage">
<methods>
<include name="VerifyUserLogin"></include>
</methods>
</class>
</classes>
</test>
</suite>
I have implemented this in Java.
If you are going to run the test cases in parallel then you would need to have a separate webdriver instance associated with each test. You can't share the instance across tests in a multithreaded environment.
As for abstracting the initialization of the webdriver instance, there are several ways out there. You could perhaps write a base TestCase class that would build the webdriver instance. Each of your test cases will then extend TestCase class, along those lines.
In TestNG you can control the thread count by specifying the parameter -threadcount in testng.xml. Check out the documentation here. If you are launching TestNG programatically then you can use setThreadCount method. Check Java docs here.
Under one package:
Test1.java -> Have #BeforeTest and #AfterTest to launch the browser and close the browser respectively.
Eg:
public class Test1 {
public static WebDriver driver;
#BeforeTest
public void open_browser()
{
driver = new FirefoxDriver();
}
#AfterTest
public void close_browser()
{
driver.close();
}
}
Login.java
public class Login {
#Test
public static void logintest{
Webelement ele1 = Test1.driver.findElement(...);
}
}
In your XML file:
<test name = "MyTest">
<classes>
<class name = "Test1"></class>
<class name = "Login"></class>
</classes>
</test>
This will make use of driver instance created in the Test1 file.
Hope it helps !! :)
The Best Way to handle this is:
Have one BaseClass where you just initate the Browser.
public class BaseClass
{
public static Webdriver driver;
#BeforeSuite
public void Launch_Browser()
{
webDriver Driver= new FirefoxDriver();
}
}
Then Extend the BaseClass to your all other classes -by usings extend
public class Class1 extends BaseClass
{
#Test
public void TC1()
{
//PASS
}
}
and so on. The important thing is you should declare webdriver driver as public static in BaseClass.

Resources