How to run one test against multiple sites using Selenium and TestNG - java

Given 3 web applications under test with given URLs:
www.A.com
www.B.com
www.C.com
How do I proceed to design a way using Selenium to run a single TestNG test against these three browsers and print out the results.
Current Strategy:
I have a java class with a main method, a properties file containing the the 3 urls listed above.
In this class i have a while loop that parses these properties file like below snippet, and for each url, programmatically calls an ant task that automates the build from compilation to test-run to result archiving. The problem is that after the first run completes, it doesn't return to the while loop to do it again. You might ask why i want to run it three times. The idea as already explained is to be able to run a suite of tests against multiple websites automatically and printout results without intervention. Code Snippet
try {
reader = new BufferedReader(new FileReader(new File(filename)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
while((line=reader.readLine()) != null){
//call ant target to archive result
userprops.setProperty("url", line);
org.apache.tools.ant.Main.start(target, userprops, loader);
}
}catch (IOException e) {
e.printStackTrace();
}
I hope somebody understands what am trying to do and can help me understand why the while loop terminates after the first test run. Also maybe can offer another easier strategy with TestNG.
thanks Guys. Y.ou guys Rock!!

It seems to me that if you are using ANT you shouldn't need your class. I would just use three targets and assign the different properties within those targets.

Related

How to explicitly fail a test step in Extent Report?

Background
I am using Extent Report Cucumber Adapter for my Cucumber based test automation framework built using Java which is running on Junit. I am using AssertJ assertions for the test conditions.
Scenario
One of the test scenarios require to test all the links on a web page. I have written the code for the same and it's working fine. I am using AssertJ assertion for the test condition under a try block and catching the SoftAssertionError so that my test execution doesn't halt because of the exception and continue validating all the remaining links even if it finds any broken link.
The report mentions the links which are found broken. However, ideally this step should get failed as the script found some broken links. But the report marks the overall step as passed and as a result the scenario is also marked as passed. Now I am not able to figure out how can I mark the step as failed in my Extent Report provided there are some links found which are broken. Kindly suggest a way to do this. I am providing a small snippet of my code for a better understanding.
public void ValidateAllLinks(String linkURL) {
try
{
URL url = new URL(linkURL);
//Creating url connection and getting the response code
HttpURLConnection httpURLConnect=(HttpURLConnection)url.openConnection();
httpURLConnect.setConnectTimeout(5000);
httpURLConnect.connect();
try {
SoftAssertions softly = new SoftAssertions();
softly.assertThat(httpURLConnect.getResponseCode()).as("This is a broken link: " + linkURL).isGreaterThanOrEqualTo(400);
softly.assertAll();
}catch (SoftAssertionError e)
{
e.printStackTrace();
}
if(httpURLConnect.getResponseCode()>=400)
{
System.out.println(linkURL+" - "+httpURLConnect.getResponseMessage()+" is a broken link.");
ExtentCucumberAdapter.addTestStepLog("<b>" + "<font color=" + "red>" + linkURL+" - "+httpURLConnect.getResponseMessage()+" is a broken link." + "</font>" + "</b>");
}
//Fetching and Printing the response code obtained
else{
System.out.println(linkURL+" - "+httpURLConnect.getResponseMessage()+" is working as expected.");
}
}catch (Exception e) {
}
}
Your example is not a good fit for soft assertions as you are testing only one thing. Soft assertions are meant to assert a bunch of things and once you have asserted all the things you wanted to, you call assertAll().
I don't understand why you test twice httpURLConnect.getResponseCode() you could do it once, add the test step log and then fail the test with a fail() method call (either from AssertJ or JUnit)

Jenkins displays "Build Success" even when tests are failed due to error handling in scripts (try and catch block)

Note: I am unable to paste the exact framework and code as the server I work on is not accessible from outside. Hence, I will try to explain my problem in simple words and examples.
Overview - I have created a Selenium automation framework which includes TestNG, Maven (POM.XML), Test data files, Scripts and few reusable functions.
Issue I am facing - I use Jenkins to execute my scripts. Jenkins calls POM.XML file which inturn calls testng.xml file (In testng.xml file, I have mentioned the scripts to be executed)
Let's say, I have to perform login action
Main Script
#Test
Public void maintest ()
{
//I use Extent reports for reporting purpose and hence I have created extent
//reporting reusable function which is called in the below fashion.
//If Login method returns pass, ExtentReportingFunc passes Pass to its
//function and displays Pass for that particular Login step in the report.
ExtentReportingFunc (Login(UserName, Password));
}
Reusable functions
Public String Login (String UN, String Pass)
{
//Sendkeys and set UN
driver.findelement (By.id("username")).sendkeys(UN);
//Sendkeys and set Password
driver.findelement (By.id("password")).sendkeys(pass);
//Click Login
driver.findelement (By.id("login")).click ();
//Verifying the message "Welcome User" is displayed after login
try
{
if (driver.findlement (By.id("welcomemessage")).isdisplayed ();
{
return pass;
}
} catch (Exception e)
{
//If welcome message is not found then return fail to the Reporting function
return "fail";
//Below code will be unreachable which is correct as per Java but that is the challenge.
// I tried several ways to find a work around to return fail as above as
// well throw exception but no luck till now.
// Upon throwing exception in the below way, Jenkins displays build as
//failed. If it is not done, though the script has failed,
//Jenkins displays "BUILD PASSED"
throw e;
}
}
//Extent Reporting function
ExtentReportingFunc (String status)
{
log.report (status);
}
Here, the challenge is - In the catch block, If I DO NOT mention "throw e", Jenkins won't understand that the failure has occurred and display "BUILD PASSED" in it's console output. I want it to display "BUILD FAILURE" in Jenkins console. Reason why I want it to display "BUILD FAILED" is - I have integrated JIRA with Jenkins. Only when jenkins show BUILD FAILED, it logs automatically bugs to JIRA. If it is "BUILD PASSED" and though finished status is UNSTABLE, no failures will be displayed in the test result section of Jenkins NOR it logs any bugs in JIRA.
However, that time I won't be able to pass return "fail" to the main reporting function so that it can display login step as failure in the report.
I understand, as per JAVA we can either throw or return in the catch block but not both. Is there any other way we can make this work?
I already had created end to end framework but later realised this problem when I started integrating with Jenkins (or else everything was fine till then).
Why Don't you add assert fail inside you catch statement, that way you are forcing testng test to fail when its inside the catch statement
org.testng.Assert.fail("Im failing here due to ... you can add your e message here");
Just add the line of code before
return "fail";
and keep the rest of the function as is
You can solve this problem by using asserts, so whenever your condition doesn't met the assert will fail and so will your test case and jenkins will show the status of the build as "UNSTABLE" instead of "PASS".
For example, in the above example, instead of using try catch and if condition in the try, it can be solved by a single line of assert which will also give you your desired build status as well.
You can replace the above code with:
Assert.assertTrue(driver.findElement(By.id("welcomemessage")).isDisplayed(), "Element is not present on the page");
So in this, if the element is not displayed on the page, assert will be failed as it is expecting true value but will get false and your jenkins build status will be shown as unstable.

Is it possible to add a variable where code should be?

I am currently trying to create an automation framework using Java and Selenium.
I want to create a line of code which essentially can read any input and make it a line of runnable code. For example, in an external file, a user could post 'id' into a field, that field will then be read by my program and execute the line. driver.findElement(By.id(.......)
Currently I'm using a bunch of if statements to do this for each identifier e.g. id, cssSelector, Xpath etc etc but then I'll need to do the same for the actions used by the program .click, .sendKeys etc so the program will just keep expanding and look overall very messy.
Is there a solution that would allow me to do this in a nicer way or am I stuck with my original approach?
Reflection is probably the most direct way to solve this. It essentially allows classes and methods to be looked up by their string names.
Here's a fag-packet example of how you might approach this using the snippet you provided, but I suggest you read some documentation before diving in.
Element findElementReflectively(Driver driver, String elementType, String thingToSearchFor) {
try {
Method m = By.class.getMethod(elementType, String.class);
if(!Modifier.isStatic(m.getModifiers())) {
throw new NoSuchMethodException("'By' method is not static.");
}
return driver.findElement(m.invoke(null, thingToSearchFor));
} catch (IllegalAccessException | NoSuchMethodException e) {
throw new IllegalArgumentException("Unknown element type: " + elementType, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Failed to find requested element.", e.getCause());
}
}
It depends on what you actually want to do.
Reading an id from a file and then execute code can be achieved through config file with this : Properties
Or if you want to execute full input code just search a little bit more
How to execute console or GUI input as if it was actual Java code?

TestNG try/catch not working properly

I am working on a test automation framework that someone previously built. The framework reads test data from an excel file and uses Selenium webdriver to control the browser and perform tests.
I am adding functionality to this framework by adding a TestNG class that reads data from a CSV file. Some functions in the current framework use try/catch. So when I call these functions from the TestNG class, TestNG will always say that the test passed, no matter what.
For example, this is from the current framework;
if (enterValueInBox.length() >= 1) {
try {
browserActions.typeValueInTextBox(myDriver, enterValueInBox);
} catch (Exception e) {
System.out.println("enterValueInBox failed");
}
}
This if statement is inside a function. It doesn't matter whether this functions works or not, it will always pass in TestNG. Even if Selenium can not find the element for example.
How can I work around this? Do I have to change the try/catch?
EDIT: Another example from the same function. The function basically consists of several if statements just like the two I am showing here. They all have the same signature, so an if statement with try/catch inside. Also worth mentioning, the function/class I am calling is not a TestNG class. So I built a TestNG class, and calling a non-TestNG class->method.
if (backSpaceInTextBox.length() > 1) {
try {
wa.handleSeleneseCommand(myDriver, Properties.TIME_TO_WAIT,
"niet gelukt");
browserActions.doBackSpaceInTextBox(myDriver,
backSpaceInTextBox);
} catch (Exception e) {
System.out.println("Could not do backspace");
}
}
Your tests are passing because test function completes
without any assertion failures
without exception thrown from test method
In your case, you should do one of
do not catch exceptions at all. Declare test methods to throw those exceptions
catch exception and fail test (Assert.fail)
Try this :
if (enterValueInBox.length() >= 1)
{
try
{
browserActions.typeValueInTextBox(myDriver, enterValueInBox);
}
catch (Exception e)
{
Assert.fail("EnterValueInBox failed", e);
}
}
Your test will fail when an Exception is thrown.

Sending a password to a Java Process

I am trying to access SVN through the process command in Java as part of a larger GUI to see what files are on the SVN. After much research, I have significantly refined my methods, however I still cannot accomplish it. If I run the code in the GUI, it just hangs. To discover what that problem was, I simplified it and ran it as a console program. When I ran it there, it displayed a request for my GNOME keyring. My code enters the password but the console does not seem to accept it. My code follows:
public class SvnJavaTest{
public static void main(String[] args){
try {
String[] commands = {"svn", "ls", "https://svnserver"};
Process beginProcess = Runtime.getRuntime().exec(commands, null, new File("/home/users/ckorb/Desktop"));
BufferedReader br = new BufferedReader(new InputStreamReader(beginProcess.getInputStream()));
BufferedWriter write = new BufferedWriter(new OutputStreamWriter(beginProcess.getOutputStream()));
write.write("password");
write.flush();
String line=br.readLine();
while (line != null){
System.out.println(line);
line =br.readLine();
}
br.close();
write.close();
beginProcess.waitFor();
} catch (IOException e1) {
e1.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
I don't get any errors running this and if I type in my password manually into the console and then run it, it works because it remembers my password. I have looked and found that there are some packages that would automatically enter my keyring on login but that isn't really an option. Thank you very much.
The main problem with a solution like this is that you don't really have control over stdin and stdout. A malicious person can wrap the svn command with a shell script that makes a copy of the stdin (thereby capturing all the passwords your program transmits). While shell's flexibility makes it great in so many ways, it is the same flexibility that you are connecting to, and you'd better be comfortable with it (and it's consequences).
That is the real reason why it is better to use a Java API to use the client, there's a much smaller chance of injecting code which captures sensitive data (and better error reporting).
Use the SVN Kit library instead.
Better to use svn java API (there are several, I am not sure which one is better), it's more straightforward solution.
Answering you question - you could provide auth info in the url: https://username:password#svnserver

Categories

Resources