Archive

Archive for the ‘JSF’ Category

Seam,EJB3,Oracle Code Example .zip

January 5th, 2009

In my post JBoss Seam, JSF,Oracle and EJB3 Hello World  I gave a step by step example on how to set up a basic example using all of the aforementioned technologies,

I also provided code examples for each file you would need however over the Christmas holidays I discovered that the plug I use to display code did not correctly format XML files. I dont know why it just didnt. As I was on holiday I didnt have access to my machine which had my source code on it so it had to go uncorrected till today..

I have taken all the examples I give in the post zipped them up and uploaded them you can download the zip file at http://jdick.co.uk/blog/code/JSFExample.zip this is only the source code there are no supporting jars included in this you have to go find those yourself from the sources I mention in the post JBoss Seam, JSF,Oracle and EJB3 Hello World.

So download, use, learn, enjoy and please feel free to comment if you find I have screwed something up and Ill do my best to fix it

EJB3, JSF, Seam, Source, Tutorial , , ,

Introduction to testing with Selenium

December 15th, 2008

Selenium is a framework which allows for testing of a front end web application. This can be down via the Selenium IDE which allows you to “record” tests in firefox, using this way you carry out any function you wish on your site and Selenium monitors the steps carried out and is translates them into a series of commands which can then be run later to replay and carry out the test.

This makes it very easy for non programmers to create tests as it requires no code to be written. However any change made to the site requires the whole test be rerecorded, and the IDE only works in Firefox. In order to get something that works in IE the output of the IDE recorded test can be outputted into of the following programming languages Java, C#, Perl, Python and Ruby. Once in tests are have be outputted to a programming language, they can be modified and run against any browser using another Selenium tool the Selenium Remote Control

Personally I prefer using the remote control as it is easier to tweak a test in Java than it is to record a test in the IDE after I make a change to the layout of a site.

Using the Hello World JSF tutorial I created in this post JBoss Seam, JSF,Oracle and EJB3 Hello World I will show you how to quick it make a few changes to this application to implement to simple acceptance testing.

1 download junit.jar

2 download Selenium RC 1.0 beta 1

3 extract it somewhere, mine has been extracted to C:\selenium-remote-control-1.0-beta-1-dist\selenium-remote-control-1.0-beta-1

4 copy C:\selenium-remote-control-1.0-beta-1-dist\selenium-remote-control-1.0-beta-1\selenium-java-client-driver-1.0-beta-1\selenium-java-client-driver.jar to the lib directory of your JBoss server C:\jboss-4.2.3.GA\server\default\lib

5 create a new batch file selenium.bat to control the Selenium test server. This is the application which carries out the tests.

c:
cd C:\selenium-remote-control-1.0-beta-1-dist\selenium-remote-control-1.0-beta-1\selenium-server-1.0-beta-1
java -jar selenium-server.jar -Dhttp.proxyHost=localhost -Dhttp.proxyPort=4447 -port 4447

Ok so now selenium is installed its time to update our application. Add the selenium-java-client-driver.jar to your project classpath. Also add Junit.jar to your classpath this will let us use the Junit annotations.

2 changes are required to be made to the build.xml to include the selenium-java-client-driver.jar and a change is required to register.xhtml in order to make testing the form elements easy.

build.xml


< ?xml version="1.0"?>
<project default="deployDevelopmentEar">
<target name="createBeansJar" depends="clean">
<mkdir dir="${dest.dir}/beans"/>
<javac compiler="modern" source="1.5" destdir="${dest.dir}/beans">
<classpath location="${lib.dir}/jsf-api.jar"/>
<classpath location="${lib.dir}/jboss-seam.jar"/>
<classpath location="${lib.dir}/javaee.jar"/>
<classpath location="${lib.dir}/hibernate3.jar"/>
<classpath location="${lib.dir}/hibernate-annotations.jar"/>
<classpath location="${lib.dir}/junit-4.1.jar"/>
<classpath location="${lib.dir}/selenium-java-client-driver.jar"/>
<classpath location="${lib.dir}/ojdbc14.jar"/>
<src path="${beans_module.src}"/>
</javac>
<copy file="${beans_module.src}/seam.properties" todir="${dest.dir}/beans"/>

<jar destfile="${dest.dir}/jsf.jar" basedir="${dest.dir}/beans">
<metainf dir="${beans_module.src}/META-INF">
<include name="**/*.*"/>
</metainf>
</jar>
</target>
</project>

register.xhtml

< ?xml version="1.0" encoding="utf-8"?>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">

<head>
<title>Register New User</title>
</head>
<f :view>
<h :form>
<s :validateAll>
<h :panelGrid columns="2">

<div id="Name">Name:</div><h :inputText value="#{userdetails.name}" required="true" id="NameInput"/>
<div id="Address">Address:</div><h :inputText value="#{userdetails.address}" required="true" id="AddressInput" />
<div id="City">City:</div><h :inputText value="#{userdetails.city}" required="true" id="CityInput"/>
<div id="Email">Email:</div> <h :inputText value="#{userdetails.email}" required="true" id="EmailInput" />
<div id="PhoneNumber">Phone Number:</div><h :inputText value="#{userdetails.phoneNumber}" required="true" id="PhoneNumberInput" />
<div id="Age">Age:</div><h :inputText value="#{userdetails.age}" required="true" id="AgeInput" />
</h>
</s>

<h :messages/>
<h :commandButton value="Register" action="#{userBean.count}" id="RegisterButton"/>
</h>
</f>
</html> 

updated versions of both files can be downloaded here: <UPLOAD FILE LOCATION TODO>

Now to implement our new test files:

JSFExample/beans/Test

create a new package Test under JSFExample/beans

Browser.java

This is our testing base class it configures our URL we want Selenium to test, the server port assigned to the variable

private static final int SERVER_PORT = 4447; is the port used to start the selenium and is the same one as specified in the selenium start up script.


package Test;

import com.thoughtworks.selenium.DefaultSelenium;

public class Browser {

  public static DefaultSelenium getInstance(String browser) {
    if (sel == null) {
      newBrowser(browser);
    } else if (browserNameChanged(browser)) {
      stop();
      newBrowser(browser);
    }
    return sel;
  }

  public static void stop() {
    sel.stop();
    sel = null;
  }

  public static void openPage(String page) {
    if (sel.isAlertPresent()) {
      System.err.println("Unexpected alert with message \"" + sel.getAlert() + "\"");
    }
    sel.open(LOCAL_ADDRESS + page);
    try {
      Thread.sleep(100l);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static boolean isElementPresent(String... elements) {
    for (String element : elements) {
      if (!sel.isElementPresent(element)) return false;
    }
    return true;
  }

  public static boolean isVisible(String... elements) {
    for (String element : elements) {
      if (!sel.isVisible(element)) return false;
    }
    return true;
  }

  private static void newBrowser(String browser) {
    sel = new DefaultSelenium(SERVER_HOST, SERVER_PORT, browser, LOCAL_ADDRESS);
    sel.start();
    sel.setTimeout("25000");
    lastBrowser = browser;
  }

  private static boolean browserNameChanged(String browser) {
    return !browser.equals(lastBrowser);
  }

  private static DefaultSelenium sel;
  private static final int SERVER_PORT = 4447;
  private static final String SERVER_HOST = "localhost";
  private static final String LOCAL_ADDRESS = "<a href="http://localhost:8080/web/">http://localhost:8080/web/</a>";
  private static String lastBrowser = "";
}

 

BrowserTest.java

This class specifies which web browsers I want the tests to be run on. In my post Running Multiple versions of Internet Explorer on your PC I set up my PC to run IE 5.5 IE6 and IE 7 on the same PC this class allows me to test on all these different versions by specifying them.

*iexplorer runs the PCs default version of Internet Explorer in this case IE 7 and

*firefox runs the default version of Firefox.

1. Any additional browsers can be used by specifying the full path however these may have issues with proxies, more about proxies later, and may not be supported by Selenium IE 5.5 is not supported. However some features still work. If you just want to test your default IE and Firefox comment out these to lines

//list.add(new String[]{"*custom C:\\Program Files\\MultipleIEs\\IE6\\iexplore.exe"});
// list.add(new String[]{"*custom C:\\Program Files\\MultipleIEs\\IE55\\iexplore.exe"});


package Test;

import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.AfterClass;
import java.util.ArrayList;
import com.thoughtworks.selenium.DefaultSelenium;

@RunWith(Parameterized.class)
public class BrowserTest {

  @Parameterized.Parameters
  public static ArrayList data() {
    ArrayList<string []> list = new ArrayList</string><string []>();
   list.add(new String[]{"*iexplore"});
   list.add(new String[]{"*firefox"});
   list.add(new String[]{"*custom C:\\Program Files\\MultipleIEs\\IE6\\iexplore.exe"});
   list.add(new String[]{"*custom C:\\Program Files\\MultipleIEs\\IE55\\iexplore.exe"});
    return list;
  }

  @AfterClass
  public static void closeBrowser() {
    Browser.stop();
  }

  protected DefaultSelenium sel;
}

NavigationTest.java

This is our class where we specify our tests. As it extends BrowserTest.java it will execute on this class on each of the browsers in the BrowserTest list.

This class is very simple It contains a setup method, 2 tests and a clean up section.

The setup method is specified with @before and this opens the browser at the correct page.

Test 1 is checkFieldsArePresent this uses the ID on the input fields and simply makes sure they are present on the web page

Test 2 FillForm() enters detail into each of the fields on the form using the ID of the textInputFields to put the correct text in the correct fields. It then presses the register button, waits 5 seconds for the next page to be displayed and checks to see if the new person has been added,

As I am using an Oracle database I need to remove the details of the person I just added to prevent my database filling with duplicate data which could corrupt future tests. This is simply a JDBC connection to the database which executes a DELETE script on the person I just created.


package Test;

import org.junit.*;
import static org.junit.Assert.assertEquals;
import java.sql.*;
import com.thoughtworks.selenium.*;

public class NavigationTest extends BrowserTest {
  public String browser = "";

  public NavigationTest(String abrowser) {
    browser = abrowser;
    sel = Browser.getInstance(browser);
  }

  @Before
  public void seedDatabase() throws SQLException {
    Browser.openPage(TREE);
  }

  @Test
  public void checkFieldsArePresent() {
    waitFor(1000L);
    assertEquals(sel.getText("id=Name"), "Name:");
    assertEquals(sel.getText("id=Address"), "Address:");
    assertEquals(sel.getText("id=City"), "City:");
    assertEquals(sel.getText("id=Email"), "Email:");
    assertEquals(sel.getText("id=PhoneNumber"), "Phone Number:");
    assertEquals(sel.getText("id=Age"), "Age:");
  }

  @Test
  public void FillForm() {
    String[] browserArray = browser.split(" ");
    sel.type("j_id2:NameInput", "Test Guy " + browserArray[0]);
    sel.type("j_id2:AddressInput", "Test House");
    sel.type("j_id2:CityInput", "Test Town");
    sel.type("j_id2:EmailInput", Guy @ Test. com);
    sel.type("j_id2:PhoneNumberInput", "55554323434");
    sel.type("j_id2:AgeInput", "9");
    sel.click("j_id2:RegisterButton");
    waitFor(5000L);
    Assert.assertTrue(sel.isTextPresent("Test Guy " + browserArray[0]));
  }

  private void waitFor(Long millisecs) {
    try {
      Thread.sleep(millisecs);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  @After
  public void cleanUpDB() {
    try {
      String[] browserArray = browser.split(" ");
      DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
      Connection con = DriverManager.getConnection
        ("jdbc:oracle:thin:@DBURL", "USERNAME", "PASSWORD");
      Statement stmt = con.createStatement();
      stmt.executeQuery("DELETE from Users where name='Test Guy " + browserArray[0] + "'");
      con.commit();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  DefaultSelenium sel;
  private final String TREE = "register.seam";
}

Acceptance.java

This class would form the core of a test suite, I would have all the test implementation classes for my site listed here, and running Acceptance would run all the tests for my suite.


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

@RunWith(Suite.class)
@Suite.SuiteClasses({
  NavigationTest.class

  })
public class Acceptance {
}

Testing

If you implement these 4 classes and specify your own database information in NavigationTest

Start the JBoss and run the selenium.bat

Now running Acceptance.java will cause a browser window to pop up which looks like

 

That concludes this tutorial on getting the Selenium test framework working with a simple JSF example.

 My personal view of Selenium is good, i have been using it for a while and it is relativity  simple to understand, and get working for most web interactions like clicking , typing etc. I haven’t been able to make it work yet with drag and drop using code written in the remote control. If anyone has please post a comment with a link on how you managed it. It can also be a bit flaky when it comes to timings. You often have to implement a wait for a few seconds otherwise it goes to fast and failed a test before a component has had time to load, which is what happens in this example if you don’t put a wait after the registerButton is clicked. 

Links and Tips

API

Selenium API

Forums

the forums content is OK however they are horrible to try and navigate, also expect lots of posts with no answers, I find most of these are for questions I am asking.

http://clearspace.openqa.org/community/selenium
Selenium Forum

Timing

If a test fails and it looks like it should pass It will probably be down to timing. Implement a few seconds wait before the failure point and it will probably work.

ID or xpath

You can specify a element either with the xpath or the element id, obviously ID is better and removes the need to mess about with firebug to try and find the xpath. You also don’t need to change every test if you make a simple UI change.

Proxy

In my example I use IE 6 and IE 7 however as I specify IE 6 as a custom browser you will have problems if the proxy to the selenium server is not setup. You wont have this problem with one of the default browsers.

To set the proxy for IE 6. open IE 7.. yes IE 7, go Tools > Internet Options > Lan settings and in the Proxy server box type localhost and in the port type 4447 and unclick bypass proxy server for local addresses.

This will stop your normal IE from working if you are behind a proxy but will make you tests work in IE 6, so remember to note down the original info before you change it.

JSF, Testing, Tutorial, selenium , , , , ,