0

I will try to give as much information as possible. I'm using TestNG framework with Java.+Selenium Below are 2 custom methods i have written.

// Checks if a WebElement is present on the screen
public boolean isElementPresent(WebElement element) {
    try {
        element.isDisplayed();
        return true;
    } catch (RuntimeException e) {
        return false;`
    }
}


// Used to click on the desired element
public void clickWebElement(WebElement element) {
    isElementPresent(element);
    element.click();
}


protected void enterDataintoField(WebElement element,String fieldData) {
    isElementPresent(element);
    element.click();
    element.clear();
    element.sendKeys(fieldData);    
}

Now assume there is a link say Login. Clicking on Login opens a page which has 2 fields username and password.The below code is used to login.(Login, username ,password and logoutBtn are webElements)

  public void login(String username, String password)
 {
 try{
 clickWebElement(Login);
 //pause few seconds for page load
 enterDataintoField(username, "Adam");
 enterDataintoField(password, "mypassword");
 //pause few seconds to login
 Assert.assertTrue(isElementPresent(logoutBtn));
 }catch({**ErrorType**} e){
 //Some code here
 }
}

Now comes my issue. If i set the ErrorType to RuntimeException in the above catch block then incase of any issues like say the username field is not displayed or the login button is missing, then this catch block will be able to catch the issue. BUT this catch block will not be able to catch the Assert statement above which validates whether the login was successful.

Similarly if i use AssertionError above then the catch block will be able to catch scenarios where the assert fails but will not be able to catch any other issues. Hence i need some advice on what i can do here. I have thousands of lines of code so i don't want to use both RuntimeException and AssertionError catch blocks everywhere(As in 2 catch blocks. I want a single catch block)

Any other suggestion or best practice would be really appreciated.

Shrik97
  • 59
  • 1
  • 1
  • 8
  • My question isn't necessarily on this one single thing. If there is a better way to go about doing the same thing using testng don't hesitate to show it. – Shrik97 May 19 '17 at 14:08
  • Can you elaborate more on what it is that you do in the catch block? In test scenarios catching exceptions is usually only necessary if you want to assert the exception itself. For instance, is it the correct Exception type, is data set you need to handle the exception... – Christian Ziegler May 19 '17 at 14:11
  • Your logic is flawed. isElementPresent returns a boolean yet you are not acting upon that result, so if the element does not exist, it returns false from the try/catch, but since you are calling it from other methods disregards the result and continues anyway. It should be more like if (isElementPresent(element)) element.click(); – Bill Hileman May 19 '17 at 14:43
  • Don't do that. Catch each different thing differently, and don't catch test Assertion errors at all. Assertion errors are `Error` types and not meant to be caught by the test itself but passed on up to the test reporting mechanism. – Lew Bloch May 19 '17 at 15:42
  • Elaborating a bit more . Once i do the assert like in the example Assert.assertTrue(isElementPresent(logoutBtn)); i immediately call a "pass" reporting method like this "report.pass("This step passed"); wheras in the catch block i have a "fail" reporting method like this "report.fail("This step failed"); . So if the assert condition is true it will go to the report pass and if it fails it will goto catch block where the report fail is called – Shrik97 May 20 '17 at 03:46

4 Answers4

1

Your catch block only catches Throwable objects that extend java.lang.Exception and AssertionError is an Error (as it extends java.lang.Error) however, If you really want to catch AssertionError in catch block - you need to use following catch block syntax :

catch (AssertionError e) { ... }

So this means that You can't handle both Exceptions and Errors in same catch block; but what you can do is try and use two separate catch blocks one to handle exceptions and other one to handle Errors like below:

    try{

    }catch(Exception e){
      ...
    }
    catch(AssertionError e){
      ...   
    }
Kushal Bhalaik
  • 3,349
  • 5
  • 23
  • 46
  • i know this is possible but as i mentioned in my initial post this is exactly what i want to avoid. Also i don't necessarily need a catch block for AssertionError. All i really want is to check a condition like Assert.assertTrue(isElementPresent(logoutBtn)); and if it fails i want to call some methods. – Shrik97 May 20 '17 at 11:57
  • if you necessarily don't need handling AssertionError, you can use throws AssertionError in your method signature and rest can be handled in standalone try/catch block – Kushal Bhalaik May 20 '17 at 12:42
0

Here is the Answer to your Question:

You need to address a lot of things here as follows:

  1. You have defined isElementPresent(WebElement element) to return boolean but when you are calling isElementPresent(element); you are not using the return boolean status at all. So my take will be to check the boolean status within a for loop and then proceed for element.click();
  2. The implementation of Assert.assertTrue is incorrect here as in Assert.assertTrue(isElementPresent(logoutBtn));. Assertions from TestNG are designed to validate the @Test results. These results are the information to you and your organization which you may want to keep track. Never write Assertions with in try block only to catch the Failed Assertion in Catch block & forcefully convert them to status Pass.
  3. To understand the relation between try/catch & Assertions you may consider looking at this discussion.
  4. In your code you are trying to Assert the presence of Logout button as Assert.assertTrue(isElementPresent(logoutBtn));. That should not be an Assertion. Rather you can induce an ImplicitlyWait or ExplicitWait for the Logout button to be clickable.
  5. Now, the Answer you would be looking for is Where and How do you implement Assertions? Definitely the Assertions would be written out of try block. Assertions can be applied on Page Title, Page Source or any Element present on a page. As per best practices there are 2 ways to implement Assertions. First one, Assertions can be part of your Test Class. Second one, as per PageFactory in POM, Assertions should be handled in a seperate package/class. You need to call the methods of the class which contains the Assertions.
  6. In your code if you want to add any Assertion, you can add it initially when you open the intended URL and next you can add one more Assertion once you login into the Web Application validating the Page Title.

Let me know if this Answers your Question.

Community
  • 1
  • 1
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
0

All this assertion/verification and wait related implementation supposed to provide by the underlying automation framework. You can use one of available efficient automation framework like QAF. Your implementation may look like below:

// Checks if a WebElement is present on the screen
element.isPresent()
// verify  WebElement is present on the screen
element.verifyPresent()
// assert  WebElement is present on the screen
element.assertPresent()

//actions and other element methods no need to wait
element.click();

It has also Predefined step library that you can use. In that case your login can look like below:

public void login(String username, String pwd){
    //loc provided in locator file
    sendKeys(username, "username.txt.loc");
    sendKeys(text, "password.txt.loc");
    click("login.btn.loc");
}

IF you want to use BDD

When send keys 'my text' to 'username.loc' 
And send keys 'my text' to 'password.loc' 
And click on 'login.loc'
They verify 'welcome.msg.loc' is present

You can refer qaf-step-by-step-tutorial

user861594
  • 5,733
  • 3
  • 29
  • 45
0

Figured out what i need to do. I wrote a custom assert method :

public void myAssertTrue(Boolean condition){
    try {
        Assert.assertTrue(condition);
    } catch (AssertionError e) {
        e.printStackTrace();
        throw new RuntimeException();
    }
}

Modified the isElementPresent Method:

// Checks if a WebElement is present on the screen
public void isElementPresent(WebElement element) {
    try {
        element.isDisplayed();
    } catch (RuntimeException e) {
        throw e;
    }
}

With these 2 changes i can use RuntimeException catch block to catch both runtime and assetionErrors

Shrik97
  • 59
  • 1
  • 1
  • 8