Search code examples
webdriverjunit4test-suite

JUnit4 test case won't continue


I created a test suite with 2 test cases using Selenium IDE. I exported the suite as Java/JUnit4/WebDriver.

the first test case allow user to log-in the site, do a member search after the match is found, access the member's profile

the second test case: once in the member profile, click on the link 'donation' to add a pledge.

The test suite runs fine in Selenium IDE, but it hang up in Eclipse when I executed the suite. behavior in Eclipse, the first test case runs fine, the 2nd case opens up a new browser, the system required log-in (enter username and password).

I would like to know what shall I do, so the test cases 2 continues without asking user to log-in. I appreciate your help and advises.

Here is my test suite code break down into 3 sections (I removed uid and pd, due to the site is a internal site)

-test suite runner file: searchDonorAddPledge   
-test case1: searchDonorSuzy.class    
-test case2: DonorAddPledge.class

failure trace message:

  1. org.openqa.selenium.StaleElementReferenceException: Element not found in the cache - perhaps the page has changed since it was looked up Command duration or timeout: 30.12 seconds

  2. Caused by: org.openqa.selenium.remote.ErrorHandler$UnknownServerException: Element not found in the cache - perhaps the page has changed since it was looked up Build info: version: '2.31.0', revision: '1bd294d', time: '2013-02-27 20:53:56'

runner file:

import org.junit.runners.Suite;
import org.junit.runner.RunWith;

      @RunWith(Suite.class)
      @Suite.SuiteClasses
      (
        {
            SearchDonorSuzy.class,
            DonorAddPledge.class      
        }
      )

      public class searchDonorAddPledge { }

testcase 1 code:

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

public class SearchDonorSuzy 
{
    private WebDriver driver;
      private String baseUrl;
      private boolean acceptNextAlert = true;
      private StringBuffer verificationErrors = new StringBuffer();

      @Before
      public void setUp() throws Exception {
        driver = new FirefoxDriver();
        baseUrl = "https://jlaustin.tcheetah.com/";
        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
      }

      @Test
      public void testSearchDonorSuzy() throws Exception {
        // set overall speed of the test case
        // ERROR: Caught exception [ERROR: Unsupported command [setSpeed | 4000 | ]]
        driver.get(baseUrl + "/?html=openid");
        driver.findElement(By.cssSelector("input[type=\"submit\"]")).click();
        driver.findElement(By.id("edit-name")).clear();
        driver.findElement(By.id("edit-name")).sendKeys("username");
        driver.findElement(By.id("edit-pass")).clear();
        driver.findElement(By.id("edit-pass")).sendKeys("password");
        driver.findElement(By.id("edit-submit")).click();
        driver.findElement(By.id("cmp_admin")).click();
        driver.findElement(By.id("quicksearch_anchor")).click();
        driver.findElement(By.cssSelector("img[alt=\"Member\"]")).click();
        driver.findElement(By.id("search_name")).clear();
        driver.findElement(By.id("search_name")).sendKeys("suzy");
        driver.findElement(By.cssSelector("input[type=\"image\"]")).click();
        driver.findElement(By.linkText("Balagia, Suzy")).click();
      }

      @After
      public void tearDown() throws Exception {
        //driver.quit();
        String verificationErrorString = verificationErrors.toString();
        if (!"".equals(verificationErrorString)) {
          fail(verificationErrorString);
        }
      }

      private boolean isElementPresent(By by) {
        try {
          driver.findElement(by);
          return true;
        } catch (NoSuchElementException e) {
          return false;
        }
      }

      private String closeAlertAndGetItsText() 
      {
        try 
        {
          Alert alert = driver.switchTo().alert();
          if (acceptNextAlert) 
          {
            alert.accept();
          } 
          else 
          {
            alert.dismiss();
          }
          return alert.getText();
        } 
        finally 
        {
          acceptNextAlert = true;
        }
      }

}

testcase2 code:

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

public class DonorAddPledge 
{
      private WebDriver driver;
      private String baseUrl;
      private boolean acceptNextAlert = true;
      private StringBuffer verificationErrors = new StringBuffer();

      @Before
      public void setUp() throws Exception 
      {
        driver = new FirefoxDriver();
        baseUrl = "https://jlaustin.tcheetah.com/";
        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
      }

      @Test
      public void testDonorAddPledge() throws Exception 
      {
        driver.get(baseUrl + "/?nd=db_member&account_id=942&nowwritestate=i1110536420226242");

        driver.findElement(By.xpath("(//a[contains(text(),'Donor')])[2]")).click();
        driver.findElement(By.linkText("Campaign Manager")).click();
        new Select(driver.findElement(By.id("campaign_id"))).selectByVisibleText("A Christmas Affair 2012");
        driver.findElement(By.xpath("//a[contains(text(),'Add\n            pledge')]")).click();
        driver.findElement(By.id("pledge_amount")).clear();
        driver.findElement(By.id("pledge_amount")).sendKeys("100.00");
        driver.findElement(By.id("pledge_notes")).clear();
        driver.findElement(By.id("pledge_notes")).sendKeys("test pledge");
        driver.findElement(By.cssSelector("input[type=\"image\"]")).click();
      }

      @After
      public void tearDown() throws Exception 
      {
        driver.quit();
        String verificationErrorString = verificationErrors.toString();
        if (!"".equals(verificationErrorString)) 
        {
          fail(verificationErrorString);
        }
      }

      private boolean isElementPresent(By by) 
      {
        try 
        {
          driver.findElement(by);
          return true;
        } 
        catch (NoSuchElementException e) 
        {
          return false;
        }
      }

      private String closeAlertAndGetItsText() 
      {
        try 
        {
          Alert alert = driver.switchTo().alert();
          if (acceptNextAlert) 
          {
            alert.accept();
          } 
          else 
          {
            alert.dismiss();
          }
          return alert.getText();
        }

        finally 
        {
          acceptNextAlert = true;
        }
      }

}

Solution

  • Both testcases instantiate a new driver in their @Before method; this starts a new browser instance with a fresh session, so it loses the logged-in session details from any previous testcase:

    driver = new FirefoxDriver();
    

    I'd recommend looking into two alternative strategies:

    1. Instantiate the driver once per class, and put testcases into the same class which rely on using the same session.
    2. Restructure your testcases so they are independent of each other.

    1. Keeping the same session across multiple testcases

    You can make your code execution more efficient by instantiating the driver only once per class, instead of separately for every testcase. You should think of this as mainly an efficiency saving, however; I don't recommend using it as a way of linking the testcases together so that testcase 2 relies on testcase 1 having run successfully, for example.

    2. Making your testcases independent

    It's always tempting to construct testcases in sequence, so that you do testcase 1 (which includes logging in, for example) and that leads naturally on to testcase 2 (which does some further actions). However I'd warn that this will lead to problems. It makes your whole test suite more fragile - if there's a problem in testcase 1, all the testcases afterwards fail. It makes your testing less flexible - you can't just run testcase 3 to retest in isolation, and you can't pick and choose individual testcases out of the suite.

    I'd strongly recommend you look into the second strategy; so for example if testcase 1 is just testing the login routine, have it just test the login routine and then log out again. And if testcase 2 is just testing some functionality which can only be reached after login - well, make it log in so it can get to the functionality it's interested in. The fact that testcase 1 also does log in is not really relevant to testcase 2, and it's not a problem either - in fact, you can see it as an opportunity to start re-factoring your testcases to extract repeated code into a separate method call.