I am relatively new to Java, TestNG and Selenium Webdriver (3 weeks) and it seems Im not passing parameters correctly, the way TestNG wants me to.
The test runs perfectly, but then it says it failed for the following reason:
org.testng.TestNGException:
The data provider is trying to pass 2 parameters but the method com.pragmaticqa.tests.AppTest2#twoUsersSignUp takes 1
Here is my code:
public class AppTest2 {
public WebDriver driver;
public WebDriverWait wait;
#DataProvider(name = "dataProvider")
public Object[][] setUp() throws Exception {
File firefoxPath = new File(System.getProperty("lmportal.deploy.firefox.path", "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe"));
FirefoxBinary ffox = new FirefoxBinary(firefoxPath);
ffox.setEnvironmentProperty("DISPLAY", ":20");
driver = new FirefoxDriver(ffox, null);
wait = new WebDriverWait(driver, timeoutInSeconds );
Object[][] data = new Object[1][2];
data[0][0] = driver;
data[0][1] = wait;
twoUsersSignUp(data);
return data;
}
#Parameters({ "data" })
#Test(dataProvider = "dataProvider")
public void twoUsersSignUp(#Optional Object[][] data) throws InterruptedException{
//test here
}
}
You need to declare your test method with the data that you are filling in the dataprovider, so in your case, it should be
public void twoUsersSignUp(WebDriver d, WebDriverWait w).
Related
I'm running tests in Saucelabs, and need to set a capability at runtime called 'name', which is the name of the test method. This must be done to each DesiredCapabilities object coming from the DataProvider.
Then, I need to instantiate a live RemoteWebDriver object for the test to run with this capability included.
#DataProvider(name = "environments")
public static Object[] environments()
{
EnvironmentParser environmentParser = new EnvironmentParser();
CapabilitiesFactory capabilitiesFactory = new CapabilitiesFactory(environmentParser);
return capabilitiesFactory.makeCapabilities("./src/test/resources/webEnvironments.json");
}
#BeforeMethod
public void setUp(Method method, DesiredCapabilities[] capabilities) throws MalformedURLException
{
// Name the test in Saucelabs
for(int i = 0; i < capabilities.length; i++)
{
capabilities[i].setCapability("name", method.getName());
driver = new RemoteWebDriver(new URL(URL), capabilities[i]);
}
}
Error when trying to run the code:
Can inject only one of ITestContext, XmlTest, Method, Object[], ITestResult into a #BeforeMethod annotated setUp.
It turns out the array must be of type Object[]
The code below works as expected:
#BeforeMethod
public void setUp(Method method, Object[] capabilities) throws MalformedURLException
{
// Name the test in Saucelabs and create the driver
for(int i = 0; i < capabilities.length; i++)
{
DesiredCapabilities desiredCapabilities = (DesiredCapabilities) capabilities[i];
desiredCapabilities.setCapability("name", method.getName());
driver = new RemoteWebDriver(new URL(URL), (DesiredCapabilities) capabilities[i]);
}
}
My program works fine when run from my local machine with out using selenium grid with Remote Web driver. However when i set up the same test cases using selenium grid with Remote Web driver . Get message in eclipse saying:
java.lang.NullPointerExceptionat PP_OBJ_Login.Adminlogin(PP_OBJ_Login.java:38)
at PP_Main.step01_Login(PP_Main.java:86)
Now I know the above means that line 38 and line 86 is where the problem is in both classes my problem is i don't know why this is happening when I use selenium grid with Remote Web driver.
public class PP_Main {
private static WebDriver driver;
private static String homeUrl;
//private String homeTitle ="Google";
#SuppressWarnings("unused")
private boolean acceptNextAlert = true;
private static StringBuffer verificationErrors = new StringBuffer();
#BeforeClass
public static void setUp() throws Exception {
//----------This works and envokes IE browser -------
System.setProperty("webdriver.ie.driver", "C:\\IEDriverServer.exe");
DesiredCapabilities cap = DesiredCapabilities.internetExplorer();
cap.setCapability(CapabilityType.BROWSER_NAME, DesiredCapabilities.internetExplorer());
cap.setBrowserName("internet explorer");
cap.setPlatform(Platform.ANY);
RemoteWebDriver driver = new RemoteWebDriver(new URL("http://51.19.210.111:5555/wd/hub"), cap);
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
String url = "https://wfn-iat.adp.com/public/index.htm";
driver.get(url);
}
#Test
public void step01_Login() throws Exception {
PP_OBJ_Login.AdminVisiable(driver);
PP_OBJ_Login.Adminlogin(driver).click();-- -> line 86
PP_OBJ_Login.UserName(driver).sendKeys("NorfolkAutoUser6#adp");
PP_OBJ_Login.Submitbtn(driver).click();
PP_OBJ_Login.Password(driver).sendKeys("iatiat01");
Thread.sleep(2000);
PP_OBJ_Login.Submitbtn(driver).click();
Thread.sleep(5000);
}
PP_OBJ_Login.Java
public class PP_OBJ_Login {
private static WebElement element = null;
// WebElement Adminlogin
public static WebElement Adminlogin(WebDriver driver) {-- -- -> Line 38
element = driver.findElement(By.id("adminLogin"));
return element;
}
// WebElement input Field
public static WebElement UserName(WebDriver driver) {
element = driver.findElement(By.id("USER"));
return element;
}
I want this to work using selenium grid and remote web driver. Is there any way to resolve the null pointer issue?
Your Problem is, that you define 'driver' as a class member but you do not instantiate it. So it is null all the time.
public class PP_Main {
private static WebDriver driver;
private static String homeUrl;
//...
And the driver you instantiate inside setUp() is only valid inside the method itself. Although it has exactly the same name it is NOT the 'driver' you defined globally.
#BeforeClass
public static void setUp() throws Exception {
// ...
cap.setPlatform(Platform.ANY);
RemoteWebDriver driver = new RemoteWebDriver(new URL("http://51.19.210.111:5555/wd/hub"), cap);
// ...
}
Instantiate it this way instead
public class PP_Main {
private static RemoteWebDriver driver;
private static String homeUrl;
//...
#BeforeClass
public static void setUp() throws Exception {
// ...
cap.setPlatform(Platform.ANY);
driver = new RemoteWebDriver(new URL("http://51.19.210.111:5555/wd/hub"), cap);
// ...
}
This should work.
I have a basic test using TestNG. When I run the test using invocationcount = 2, threadpoolsize = 2 (just for testing), I can see in intellij that the tests is running currently but only one browser open.
Heres' my code:
public class GoogleTesting extends FluentTestNg {
// Defines the Driver
public WebDriver driver = new ChromeDriver();
#Override
public WebDriver newWebDriver() {
return driver;
}
#Test(invocationCount = 2, threadPoolSize = 2)
public void GoogleTest(){
goTo("http://google.com");
System.out.println(getCookies());
}
}
Anyone know how to fix this?
Here you have one webdriver instance and calling in two threads. You can try with thread local WebDriver as given below.
public class GoogleTesting extends FluentTestNg {
// Defines the Driver
private static ThreadLocal<WebDriver> WebDriverTL = new ThreadLocal<WebDriver>();
public void setWebdriver(Webdriver driver){
WebDriverTL.set(driver);
}
#Override
public WebDriver newWebDriver() {
return WebDriverTL.get ();
}
#beforeMethod
public void launch browser(){
WebDriver driver = new ChromeDriver();
setWebdriver(driver);
}
#Test(invocationCount = 2, threadPoolSize = 2)
public void GoogleTest(){
goTo("http://google.com");
System.out.println(getCookies());
}
}
I have some WebdriverSelenium/TestNG/Maven/Java continuous integration tests, that I refactored (removed a huge chain of inheritances) and now I've also installed Spring DI framework.
I just cant pass the parameters to the Test method (oneUserTwoUser)
This is the dataprovider
public class AppData {
public static WebDriver driver;
public static WebDriverWait wait;
final static String FILE_PATH = "src/test/resources/250.csv";
final static String FILE_PATH2 = "src/test/resources/places.csv";
public static ArrayList<ArrayList<String>> array;
public static Object[][] setUp() throws Exception {
//prepare data
//read data from CSV files
array = getCSVContent(FILE_PATH, 5);
array2 = getCSVContent(FILE_PATH2, 7);
//pass the data to the test case
Object[][] setUp = new Object[1][3];
setUp[0][0] = driver;
setUp[0][1] = wait;
setUp[0][2] = array;
return setUp;
}
This is the test class:
public class AppTest3 {
public static AppData appdata;
public static void main (String[] args) {
BeanFactory beanfactory = new XmlBeanFactory(new FileSystemResource("spring.xml"));
appdata = (AppData) beanfactory.getBean("data");
}
#Parameters({ "driver", "wait", "array" })
#Factory(dataProviderClass = AppData.class, dataProvider = "setUp")
#Test
public void oneUserTwoUser(WebDriver driver, WebDriverWait wait, ArrayList<ArrayList<String>> array) throws Exception {
Error
org.testng.TestNGException:
Parameter 'driver' is required by #Test on method oneUserTwoUser but has not been marked #Optional or defined
As described by the documentation:
Preface your setUp() function with #DataProvider(name="standardTestData")
Then remove all other annotations except for #Test(dataProvider="standardTestData", dataProviderClass=AppData.class)
3 weeks of experience with Java here.
I have these two classes - AppTest and AppTest2 and I have the same code in both of them:
Here is my code:
public class Apptest/AppTest2 {
public WebDriver driver;
public WebDriverWait wait;
#DataProvider(name = "dataProvider")
public Object[][] setUp() throws Exception {
File firefoxPath = new File(System.getProperty("lmportal.deploy.firefox.path", "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe"));
FirefoxBinary ffox = new FirefoxBinary(firefoxPath);
ffox.setEnvironmentProperty("DISPLAY", ":20");
driver = new FirefoxDriver(ffox, null);
wait = new WebDriverWait(driver, timeoutInSeconds );
Object[][] data = new Object[1][2];
data[0][0] = driver;
data[0][1] = wait;
return data;
}
#Parameters({ "driver", "wait" })
#Test(dataProvider = "dataProvider")
public void twoUsersSignUp(WebDriver driver, WebDriverWait wait) throws InterruptedException{
//test here
}
}
How can I take this code out (setUp()), make it a class and then pass those variables to the next void "twoUsersSignUp"
EDIT: Im not looking for automatic solution, I just want to refactor this, so I dont have the same code in both classes
EDIT2: After I implemented the accepted answer's solution, I now have a problem with passing the variable "driver" to the next method in the first class:
#AfterClass
public void quit () {
driver.quit();
}
How do I do that?
EDIT3: This is the #AfterClass solution:
#SuppressWarnings("deprecation")
#Configuration
#AfterClass
public static void quit (#Optional WebDriver driver) {
driver.quit();
}
EDIT4: actually EDIT3 doesnt work, it just hides the errors from Eclipse. I still can't access "driver" :(
EDIT5: I decided that I dont need to have it in an AfterClass TestNG annotation, so I removed all the unnecessary stuff and it now looks like this:
public static void quit (WebDriver driver) {
driver.quit();
}
and the variable has been declared this way:
public static WebDriver driver;
but still it doesnt work
EDIT6: fixed this by actually calling the method in the test code. Beforehand I didnt have to call it, because testng.xml had it called, but after I removed the #AfterTest annotation, it had been excluded from there!
You cannot convert a method to a class, but you can move a method to a place from which it would be shared by both Apptest and AppTest2: create a base class, and make the Apptest and AppTest2 classes extend it.
public abstract class AbstractAppTest {
public WebDriver driver;
public WebDriverWait wait;
#DataProvider(name = "dataProvider")
public Object[][] setUp() throws Exception {
File firefoxPath = new File(System.getProperty("lmportal.deploy.firefox.path", "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe"));
FirefoxBinary ffox = new FirefoxBinary(firefoxPath);
ffox.setEnvironmentProperty("DISPLAY", ":20");
driver = new FirefoxDriver(ffox, null);
wait = new WebDriverWait(driver, timeoutInSeconds );
Object[][] data = new Object[1][2];
data[0][0] = driver;
data[0][1] = wait;
twoUsersSignUp(data);
return data;
}
public abstract void twoUsersSignUp(#Optional Object[][] data) throws InterruptedException;
}
public class Apptest extends AbstractAppTest {
public void twoUsersSignUp(#Optional Object[][] data) throws InterruptedException {
...
}
}
public class AppTest2 extends AbstractAppTest {
public void twoUsersSignUp(#Optional Object[][] data) throws InterruptedException {
...
}
}
Now the code of the setUp method does not need to be repeated, and it uses the implementation of the twoUsersSignUp method provided in each of the two subclasses of AbstractAppTest.
You can't just convert a method to a class.
However, you can create new objects or modify existing objects.
Initialize your testData class like this
public class ApptestData{
public WebDriver driver;
public WebDriverWait wait;
public ApptestData() throws Exception {
File firefoxPath = new File(System.getProperty("lmportal.deploy.firefox.path", "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe"));
FirefoxBinary ffox = new FirefoxBinary(firefoxPath);
ffox.setEnvironmentProperty("DISPLAY", ":20");
driver = new FirefoxDriver(ffox, null);
wait = new WebDriverWait(driver, timeoutInSeconds );
Object[][] data = new Object[1][2];
data[0][0] = driver;
data[0][1] = wait;
twoUsersSignUp(data);
return data;
}
}
And then use that object in your test classes
public class Apptest/AppTest2 {
#Test
public void twoUsersSignUp() throws InterruptedException{
AppTestData data = new AppTestData();
//test here
}
}
The kind of refactoring you are looking for does not exists yet, at least on Eclipse.
A workaround to do it manually is explained here
By the way, in Eclipse by pressing ALT SHIFT T you will find all the current available possibilities to refactor your existent code, by extracting methods, classes etc.