I'm trying to set up a web app test suite using Selenium and Java. I am going to create 3 packages under src
Objects - used for my page objects
Tasks - used for testing methods
Tests - used for the tests
Under Tasks I created a class called CommonTasks, which is used to store methods created for testing. Here are some examples.
protected void verifyNumberOfElements(By selector, int expectedsize){
int size = driver.findElements(selector).size();
log.info("INFO: Verifying the number of elements is "+expectedsize+"");
Assert.assertEquals(size, expectedsize);
log.info("PASS: The number of elements returned was "+expectedsize+" ");
}
public static void verifyText(By selector, String expectedtext){
//verify that the expected text is present
String actualtext = driver.findElement(selector).getText();
Assert.assertEquals(actualtext, expectedtext);
log.info("PASS: "+expectedtext+" was present and verified");
}
protected void verifyElement(By selector){
//Verify that a certain selector is present in the page
smartSleep(selector);
boolean isPresent = driver.findElements(selector).size() > 0;
Assert.assertEquals(isPresent, true);
log.info("PASS: Element was found");
boolean notPresent = driver.findElements(selector).size() > 0;
Assert.assertEquals(notPresent, false);
log.info("FAIL: Element was NOT found");
}
Under the Tests package, I create a class called ABC for testing feature ABC. I have some basic steps like below
verifyText(PageObjects.ItemText, "Multiple Choice - Single Answer Radio - Vertical");
verifyText(PageObjects.Progress_PercentComplete, "0%");
The issue I am having is I don't know where to create the webdriver. I want to be able to create many test classes and call any method created in the Tasks package. I know that I need to import the class from Tasks, but can't figure out the webdriver creation part. Both the Tasks and Test packages will reference driver, so how to I make this work? Does it need to be created in Tasks.CommonTasks, or Tests.ABC?
I will also need the test to connect to SauceLabs instead of my local machine.
From the code above, all your methods in the Tasks packages are utility methods and are common to your test suite so these methods are invoked from the Test methods only where your driver was initialized already so create your webdriver in your test class and pass it on to utility methods in the tasks package.
Hope it helps
Related
As IS:
Step 1: I am creating instance of testng in servelt.doPost method.
public void dummyDoPost(){
TestListenerAdapter adapter = new TestListenerAdapter();
testNG = new TestNG();
List<Class> listnerClasses = new ArrayList<Class>();
List<String> suiteNameList = new ArrayList<String>();
Class[] classList = new Class[]{
csvOperation.class
};
listnerClasses.add(straight2bank.csvOperation.class);
testNG.setDefaultSuiteName("suite");
testNG.setListenerClasses(listnerClasses);
testNG.setTestClasses(classList);
testNG.run();
Step 2:
I have class created which will read the user choice of platform returned by servelet (Say ios, Android or Chrome).
Pro gram as below.
That an another operation
Class B{
public void platformController (Map<String,String> testDataValues){
System.out.println("Platform Controller started.");
String platformToBeExecuted = testDataValues.get("JourneyId");
System.out.println("Journey ID returned to platformController " +platformToBeExecuted);
if(platformToBeExecuted.contains("chrome")){
System.out.println("Platform to be executed: Chrome");
System.setProperty("webdriver.chrome.driver",pathToChromeDriver);
/****
To remove message "You are using an unsupported command-line flag: --ignore-certificate-errors.
Stability and security will suffer."
Add an argument 'test-type'
ChromeOptions options = new ChromeOptions();
options.addArguments("test-type");
*****/
driver = new ChromeDriver();
driver.get(urlOfApplication);
System.out.println("3");
}else if(platformToBeExecuted.contains("ie")){
System.setProperty("webdriver.ie.driver", pathToIEDriver);
driver = new InternetExplorerDriver();
driver.get(urlOfApplication);
System.out.println("2");
}else if(platformToBeExecuted.contains("iOS")){
System.out.println("Platform to be executed: iOS");
System.out.println("Platform to be executed: iOS");
suites.add(".//iostestng.xml");<-----------------
dummyServletClass.testNG.setTestSuites(suites);
dummyServletClass.testNG.run();
}
SO here I have execute the iosTestng.xml using testng.
To do this :-
1) Do I have to declare testng as static in servelt class and use the same here ?
2) Do I need to create an another instance for testng in class B?
3) Is there any way to pass an argument constructor in setTestClasses?
I'm confused, as we may be working on to run the program in parallel on a long run.
If every POST call basically represents the intention of an end-user to run some tests, then I would suggest that you resort to creating a TestNG instance per invocation. That way, you would be able to isolate the test results etc., for every invocation
1) Do I have to declare testng as static in servelt class and use the same here ?
No don't do that. You will end up causing race conditions. You should instead be declaring TestNG object as a local data member in your POST method implementation. If you don't want your POST call to be a blocking call, you can basically have your POST call create a request to run some tests into a queue and you can have a polling mechanism driven by a separate thread that feeds off of the queue and runs them using TestNG.
2) Do I need to create an another instance for testng in class B?
Yes you would need to. Essentially the idea here is to localise the TestNG instance to the set of tests that it is executing, so that there is no overlapping of results, listener invocations etc.,.
3) Is there any way to pass an argument constructor in setTestClasses?
I didn't quite understand this question. What do you mean by this? Please elaborate.
This is more of a question on test automation framework design. Very hard indeed to summarize whole question in one line :)
I am creating a test automation framework using Selenium. Mostly I am accessing the data (methods name) from an excel file.
In my main Runner class I am getting a list of test cases. Each test case has a set of methods (can be same or different) which I have defined in a java class and executing each method using java reflection api. Everything is fine till this point.
Now I want to incorporate TestNG and reporting/logging in my automation suite. Problem is I cant use #Test for each method as TestNG considers #Test = 1 Test Case - but my 1 Test case might have more than 1 methods. My methods are more like a test steps for a test case, reason is I dont want repeat the code. I want to create a #Test dynamically calling different sets of methods and executing them in Java Or defining each teststeps for a #Test. I was going through the TestNG documentation, but could not able to locate any feature to handle this situation.
Any help is really appreciated and if you have any other thoughts to handle this situaton I am here to listen.
Did you try the following?
#Test(priority = 1)
public void step1() {
//code
}
#Test(priority = 2)
public void step2() {
//code
}
You need to use "priority" for each method, otherwise it won't work.
I am fairly new to Java so forgive me if this is a silly question, but believe me when I say I really cannot find a solid answer.
This is what I'm working with:
So I'm testing a program, and the easiest way to keep it maintained and updated is to create my own library of "buttons". Everything in the library are small functions like "enterValidCredentials" and "clickLoginButton".
So let's take a look at my test cases. In a perfect world I'd be able to just:
public class progressCheck {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get("http://mail.google.com/");
enterValidCredentials;
clickLoginButton;
}
}
enterValidCredentials and clickLoginButton exist in my library of classes. I know very well that that's not going to work as written above. What, literally, is the correct way to do this?
If it helps at all, my enterValidCredentials class looks like this:
public class loginPageButtons {
private WebDriver driver;
Actions actions = new Actions(driver);
public class enterValidCredentials { // This class enters in a valid username and valid password on the login page.
public void enterValidCredentials2() {
driver.findElement(By.cssSelector("input[type=\"text\"]")).clear();
driver.findElement(By.cssSelector("input[type=\"text\"]")).sendKeys("XXXXXXXX");
driver.findElement(By.cssSelector("input[type=\"password\"]")).clear();
driver.findElement(By.cssSelector("input[type=\"password\"]")).sendKeys("XXXXXXXX");
}
}
All my other functions follow a relatively similar structure (depending on their function, of course).
You can use a unit test to check single functionalities of your classes.
The most used library to create unit tests is JUnit.
If you use an ide (like IntelliJ or Eclipse) running the test can be done with a simple command exactly as running a main method.
If you need to create mocks of your objects you can use a library like Mockito (but there are many other valid alternatives).
Note: A mock is an object that has the same interface as a complex object that is difficult to use in a test environment (for example a db connection, a file handler, a network handler).
Here is an example, I tried to imagine your code and a possible test. I assumed that clickLoginButton returns an integer just to show a possible assert statement.
Example:
#Test
public static void testCredentials() {
WebDriver driver = new FirefoxDriver();
driver.get("http://mail.google.com/");
EnterValidCredentials enterValidCredentials = new EnterValidCredentials(); // Or create a mock if necessary
// Set values if necessary
int returnValue = enterValidCredentials.clickLoginButton();
assertEquals(returnValue, 1);
}
I am working on a test suite using WebDriver and TestNG. The application under test has a "report menu" which is a set of links to a ton of different reports. The list of reports is dynamic based on a bunch of different variables. I'd like to create a #Factory which creates a distinct test case for each of these links. So far so good.
However, to discover the links, I need WebDriver initialized (to go to the page, and find all of the links), but that is happening via injection from Spring IOC, and the autowiring (using #Autowired) happens much later in the lifecycle of the test runner. All of the parameters used to construct the driver itself are also injected (base url, driver class, download directory etc), so it's not feasible in this case to create a WebDriver instance "by hand" - it has to be done via the Spring application context as configured using #ContextConfiguration annotation.
So is there a manual way to get the injection to happen this early in the lifecycle of the runner?
My somewhat poor solution to this is:
Since the #Factory method runs really early, just have it return a pre-defined size array of some "empty" test cases. Say the test is MyTest, just do:
#Factory
public Object[] factoryMethod() {
Object[] tests = new MyTest[100];
for (int i = 0; i < 100; i++) {
tests[i] = new MyTest();
}
return tests;
}
Have the test method, say test() inside MyTest run at priority=1. Have a completely separate test method at priority=0, which goes to the "menu" page using the now-instantiated WebDriver object, find the links (hopefully less than 100 of them), and go "fill in" the missing parameters in the pre-created test instances. Finally, when the MyTest instance's test() method gets called, if the parameters were not filled in, throw a SkipException to have that "extra" instance not do anything. A bit clunky, but working.
I'd downvote this answer based on the dirty feeling it gives me.
I have just started using selenium grid with Testing tool for a web testing.
I have a class with this method #Test, I have hardcoded the URL here and wrote multiple methods with different URLs. but i want to pass those URL values from a txt file and the class should launch the
methods parallely for each URL from the txt file. please let me know how I can do it
#Test(description = "Showing bing")
#Parameters({"seleniumHost", "seleniumPort", "browser", "webSite"})
public void bing(String seleniumHost, int seleniumPort, String rowser, String webSite) throws Throwable {
try {
startSeleniumSession(seleniumHost, seleniumPort, browser, webSite);
Base b = new Base();
b.setInitialUrl("http://www.bing.com");
b.setMaxCount(30);
AssertJUnit.assertTrue(b.InitiateTest());
} finally {
closeSeleniumSession(); }
}
Can I use #Factory annotation here? Can you help me how I do write that class and place it where? I'am not using testng.xml here.
Please help.
To pass multiple data to your test, you can use testNG dataprovider. Details are clearly mentioned here