Pages

Tuesday, August 26, 2014

User Acceptance Testing with Selenium and Cucumber

In the last implementation project I participated in we applied the Behavior Driven Development approach where the user stories are defined in Given-When-Then style. In this article I want to describe how I combined Cucumber with Selenium in order to automate our User-Acceptance Tests using Behavior Driven Development.

For running automated BDD tests there are some free frameworks available (a brief comparison of BDD frameworks). We decided to go for Cucumber because it served all our requirements, has a good documentation with good examples and is pretty easy to get it up and running

Cucumber JUnit Test

The following listing shows a simple example that is practically the archetype for all our Cucumber tests.

@RunWith(Cucumber.class)
@CucumberOptions(
  features = { "classpath:features/example/" },
  glue = { "my.project.uat." },
  tags = { "@Example" })
public class ExampleCucumberTest {
  //empty
}
The annotations of the example in detail are:
  • @RunWith declares the TestRunner for this test, which is the Cucumber class. The test won't run without it.
  • @CucumberOptions define various options for this tests. The options are optional but are quite helpful in controlling the behavior of the test
    • features: declares a path were the BDD feature files (text files) are found. The example points to a location in the classpath. All feature files (.feature extension) below that location are considered. Multiple locations can be defined as an array.
    • glue: defines the packages where Steps and Hooks are located. Steps and Hooks contain the actual code for the tests. Multiple packages can be defined as an array.
    • tags: defines which stories should be executed. If you omit this option, all Stories are executed, otherwise only those that have one of the tags set will be run.
Of course there are more options available (see Cucumber apidoc)  but these are the options I use most. As soon as you have your first story written, you can start right away with this simple test.

BDD Feature 

The following exaple story is taken from the Cucumber documentation

@Example
Feature: Search courses
  Courses should be searchable by topic
  Search results should provide the course code

Scenario: Search by topic
    Given there are 240 courses which do not have the topic "biology"
    And there are 2 courses, A001 and B205, that each have "biology" as one of the topics
    When I search for "biology"
    Then I should see the following courses:
      | Course code |
      | A001        |
      | B205        |

With that feature in the right location you can run the above test with JUnit. Of course it will not be successful. Actually, with the default settings it will ignore all the steps unless you use the @CucumberOption(strict=true) which is recommended when you run the test as part of a quality gate.
The Cucumber documentation provides some good descriptions on Features and their syntax. You can define Backgrounds that are executed for each scenario of the feature (similar to JUnit 4 @BeforeClass) or Scenario Outlines to run the feature against a set of data. It is even possible to write your BDDs in different languages. Therefore you have to start the feature with the line following line and have all the keywords in the according language.

#language: de
Funktionalität: ...

But you have to be careful with the encoding of the Feature files and special characters. It's best to use UTF-8 as default encoding. A complete list of the keywords in other languages can be found in the Cucumber apidoc.

Cucumber Steps

When the test for the feature is run and the steps or part of it are not yet implemented, it will produce an output like this:

You can implement missing steps with the snippets below:

@Given("^there are (\\d+) courses which do not have the topic \"([^\"]*)\"$")
public void there_are_courses_which_do_not_have_the_topic(int arg1, String arg2) throws Throwable {
    // Express the Regexp above with the code you wish you had
    throw new PendingException();
}

@Given("^there are (\\d+) courses, A(\\d+) and B(\\d+), that each have \"([^\"]*)\" as one of the topics$")
public void there_are_courses_A_and_B_that_each_have_as_one_of_the_topics(int arg1, int arg2, int arg3, String arg4) throws Throwable {
    // Express the Regexp above with the code you wish you had
    throw new PendingException();
}
...

The test prints out skeletons for unimplemented steps. What you do now is to create a new step which is a simple Java class and put in one of the packages defined in the glue. Copy the skeletons into the class and implement it.
So the steps are basically what is executed for each line. It is possible to pass parameters to the steps that are extracted and converted so that steps can be reused with different values. Its also possible to define entire tables as input.

Hooks

Hooks are basically the same as steps but fulfill a similar role like the JUnit @Before and @After annotated methods, the even use the similar annotations (actually, the are named the same but are in a different package). You can trigger certain hooks using tags like shown in the following example:

@WithFirefox
Scenario: Response times with 10 users
...

and the according hook in Java will be

@Before("@WithFirefox")
public class BrowserHook {
 ...
  public void setupScenario_Firefox() {
   ...
  }
 ...

Dependencies between Hooks and Steps

In order to reuse existing code or to access the state of a particular Hook or Step instance you can create a dependency between the classes by defining a constructor that accepts a particular Hook or Step. The Cucumber JUnit runner will create instances of the according classes and inject them in classes that are dependent.
public class MyBrowserSteps {

  private BrowserHook browserHook;

  public MyBrowserSteps(final BrowserHooks browserHook) {
    this.browserHook = browserHook;
  }
The same applies to Steps so you can make one set of steps dependent on other steps.

Selenium Steps

So far I only described how to write any test with Cucumber, but for User Acceptance Testing you might want to test the actual solution. For web application that is the deployed application that is accessed by a browser. For browser automation the Selenium framework is widely known and framework of choice for most cases. It provides a recording tool (a plugin to Firefox) to record user interactions with the browser. It provides a model to access elements of the website using Java and various methods of locating elements in the browser.
For automated user-acceptance tests with Selenium and Cucumber the basic approach would be to
  1. Record actions with the Selenium Recorder
  2. Copy them to Steps classes that match your BDD
  3. Define assertions in Then step implementations
A step implemented with Selenium will look like in the following example

@When("^I push the button$")
public void i_push_the_button() throws Throwable {
  driver.findElement(By.cssSelector("div.v-select-button")).click();
}

In order to reuse steps for different browsers, I used the BrowserHook shown in on of the example on above and set-up the browser using a specific tag for each browser. The driver is first initialized upon the first call to getDriver(). In the step itself I retrieve the driver from the BrowserHook that got injected. The BrowserHook may be implemented like this

public final class BrowserHooks {
  private enum DriverType {
    headless,
    firefox,
    ie,
    chrome, ;
  }
  
  private WebDriver driver;

  public WebDriver getDriver() {
    if (driver == null) {
      switch (driverType) {
 case ie:
   driver = new InternetExplorerDriver();
   break;
        case firefox:
          driver = new FirefoxDriver();
          break;
        ...
    }
    return driver;
  }

  @Before("@WithFirefox")
  public void setupScenario_Firefox() {
    driverType = DriverType.firefox;
  }
  
  @Before("@WithIE")
  public void setupScenario_InternetExplorer() {
    driverType = DriverType.ie;
  }
  ...
}
And the step definition that uses it may look like
public class MyBrowserSteps {

  private BrowserHook browserHook;

  public MyBrowserSteps(final BrowserHooks browserHook) {
    this.browserHook = browserHook;
  }

  @When("^I push the button$")
  public void i_push_the_button() throws Throwable {
    this.browserHook.getDriver().findElement(By.cssSelector("div.v-select-button")).click();
  }
...

Aggregate Steps

One of the big advantages of a BDD framework like Cucumber is, that you can define steps that aggregate multiple steps. A good example for this is the Login Story. Although this is a point of typical discussions whether "Login User" is a valid Use Case or User Story (with regards to its business value) the requirement to allow a user to login does exists and its parameters need to be defined (whether it is via Single Sign On, Smartcard, Username/Password, Two-Factor or whatever else).
So let's assume you define a login user story such as
 Given the login screen is being displayed
 When I enter my username "xxx" and my password "yyy"
  And I push the login button
 Then I see the main screen of the application
  And I see my name being displayed in the user info box
Now you don't want to describe all these steps over and over again because the rest of the application under test requires a logged in user. So you could begin the other stories with
  • When the user "xxx" is logged in
Or even better by using a hook/tag before the story like
  • @Authenticated
Now, what you do in your code is to define a dependency to the steps class that contains the login step definitions and invoke each of them in the correct order either in a hook definition or in a step definition. The advantage of a hook is that you could combine it with other hooks to set up the test user or even persona.
public class LoginSteps {

  private BrowserHook browserHook;

  public LoginSteps (final BrowserHooks browserHook) {
    this.browserHook = browserHook;
  }


  @Given("^the login screen is being displayed$")
  public the_login_screen_is_being_displayed() {
    this.browserHook.getDriver().get(baseURL);
  }
  @When("^I enter my username \"([^\"]*)\" and my password \"([^\"]*)\"$")
  public void I_enter_my_username_and_my_password(String arg1, String arg2) throws Throwable {
    //with Selenium, put in the values in the login form
  }
  @When("^I push the login button$")
  public void I_push_the_login_button() throws Throwable {
    // with Selenium, locate the submit/login button and click it
  }
  ...
}

public class LoginHook {

  private LoginSteps loginSteps;
  private String testUser;
  private String testPassword;

  public LoginHook (final LoginSteps loginSteps) {
    this.loginSteps= loginSteps;
   
  }

  @Before(value="@PersonaXY", order=1)
  public void selectPersonaXY() {
     this.testUser = ...;
     this.testPassword = ...;
  }

  @Before(value="@Authenticated", order=2)
  public void login() {
    this.loginSteps.the_login_screen_is_being_displayed();
    this.loginSteps.I_enter_my_username_and_my_password(testUser, testUserPassword);
    this.loginSteps.I_push_the_login_button();
    ...
  }
}

And how it is used in a story

 @Authenticated @PersonaXY
 Given I see the meaningful screen
 When I do something purposeful
 Then I get a sensible result

 Conclusion

In this article I gave a brief introduction into Cucumber and how to write testcases with it. I showed how to define steps with Selenium to create meaningful, browser-based user acceptance testing and I showed how to combine thereby reuse steps and hook to create a rich user acceptance testing suite.

Friday, August 22, 2014

Developing a dynamic JEE service client with CDI (part 2)

In the previous blog entry I described how to develop an JEE service client that performs lazy lookups and is injectable to satisfy a service dependency. In this article I want to describe how to extend this service client to allow client-side service call interception.

Before I dive into the details of the interception, I want to outline the reasons why client-side call interception might be useful.

Background

In our current project we aspired a RESTful component-based architecture. For each of the components it should be possible to integrate them in a service oriented architecture via WebService, deploy them in a JEE environment accessing it as JNDI-locateable services or access them via a RESTful lightweight interface. Each component should be deployable standalone and should be operational as long as their lower-level component dependencies are satisfied. To be RESTful, our architecture followed the seven principles of REST, described in the famous thesis of Roy Fielding.

With JEE we could easily add caching behavior on the service side of a service consumer-provider relationship by adding an interceptor that serves a call with data from a cache and therefore reducing processing resource usage on the service side.

On the consumer side there is no such mechanism as to transparently intercept a service call before it is actually sent to the service. Such a client-side call interception could be of use for a range of use-cases
  • caching, to reduce network resource usage
  • error handling and fault tolerance
  • logging
  • security
 The following description uses the service client I described in a previous blog post.

Adding Interceptor support

In order to add call interceptors to the service client, we have to extend the invocation handler that delegates the service method invocation to the actual service by adding a stack of interceptors that are invoked consecutively.

When a JEE interceptors is invoked an InvocationContext is passed to the interceptor. The interceptor may decide to fully intercept the request and not proceeding the invocation further. This is behavior is needed for caching or security concern. Alternatively, interceptors may execute some additional operations before or after proceeding with the invocation which is useful for logging or error handling.

The InvocationContext is an interface introduced by JEE6. I used my own implementation of this interface where the getter methods defined by the interface simply return the values that are passed to the InvocationHandler of the dynamic proxy (see the ProxyServiceInvocationHandler of the previous blog post), the getTimer() method returns null, as I don't really need it. The main functionality of the InvocationContext however resides in the proceed() method. I used a stack (Deque) to maintain a list of registered interceptors of which each is checked whether it may intercept the method invocation or not.

The check is done in the method isInterceptedBy and does check the class of the interceptor instance as well as the method whether they both are annotated with the same the InterceptorBinding annotation. I deviated a bit from the JEE6 standard as I allowed an interceptor without an explicit interceptor binding to intercept any method invocation, but that is up to you.
The main method of my InvocationContext implementation are shown in the next listing

class ProxyInvocationContext implements InvocationContext {

  ...

  @Override
  public Object proceed() 
    throws IllegalAccessException, 
           IllegalArgumentException, 
           InvocationTargetException {
    if (!interceptorInvocationStack.isEmpty()) {
      final Object interceptor = interceptorInvocationStack.removeFirst();
      if (isInterceptedBy(interceptor)) {
        final Method aroundInvoke = interceptorMethods.get(interceptor);
        return aroundInvoke.invoke(interceptor, this);
      }
    }
    return this.method.invoke(target, this.parameters);
  }
  
  private boolean isInterceptedBy(final Object interceptor) {
    boolean hasNoBinding = true;
    for (final Annotation an : interceptor.getClass().getAnnotations()) {
      if (an.annotationType().getAnnotation(InterceptorBinding.class) != null) {
        hasNoBinding = false;
        if (getMethod().getAnnotation(an.annotationType()) != null) {
          return true;
        }
      }
    }
    return hasNoBinding;
  }
}

Instantiating Interceptors in CDI Context using DeltaSpike

Now we want to create interceptors and put them into the interceptor stack. The JEE 6 standard already defines interceptors so we could simply re-use this specification. JEE6 compliant interceptors may be used in a CDI lifecycle, that means lifecycle methods annotated with @PostConstruct or @PreDestroy are executed as well as injection of dependencies.
With the implementation of the InvocationContext described above, we need a collection of interceptor instances. In our project I used a configuration file (similar to the beans.xml where you have to define which interceptors should be loaded) where I defined the interceptor classes that should be loaded.

Creating an instance of a class by the fully qualified name of the class is trivial using reflection (i.e. Class.forName("...").newInstance()). But when you have a CDI container you want to let the container do the creation and further process the lifecycle of the the instance including dependency injection.

JEE6 itself does not provide the means for that but it defines an SPI. The Apache DeltaSpike project offers an implementation for that SPI (btw. it is developed by the same guys behind CDI in JEE6 itself). DeltaSpike allows to interact directly with the CDI container.

The following code snippet assumes, that you have already loaded the interceptor class and verified it is annotated with the @Interceptor annotation. It first checks, if a CDI environment is active, if not, the interceptor is instantiated the traditional way. If it is active, a BeanManager reference is obtained, an injection target is created using the interceptor class. This is needed to create the instance and inject dependencies to the instance. With the injection target, an interceptor Bean is created using the BeanBuilder of DeltaSpike. The Bean is a Contextual instance that is required by the manager to create a creational context. Having this context we can create a managed instance using the create method. DeltaSpikes contribution to the snippet is the BeanManagerProvider , the BeanBuilder and the DelegatingContextualLifecycle.

private <I> I createInterceptor(final Class<I> interceptorClass) 
  throws InstantiationException, IllegalAccessException {
  
  final I interceptor;
  
  if (BeanManagerProvider.isActive()) {
    final BeanManager manager = BeanManagerProvider.getInstance().getBeanManager();
    final InjectionTarget<I> target = manager.createInjectionTarget(
                                            manager.createAnnotatedType(interceptorClass));
            
    final Bean<I> interceptorBean = 
      new BeanBuilder<I>(manager)
          .beanClass(interceptorClass)
          .beanLifecycle(new DelegatingContextualLifecycle<I>(target))
          .create();
    interceptor = interceptorBean.create(
                     manager.createCreationalContext(interceptorBean));

  } else {
    interceptor = interceptorClass.newInstance();
  }
  return interceptor;
}

Conclusion

In this article I described how the Dynamic Service Client can be extended in order to provide client-side service call interception and how Interceptors (or Beans in general) can be instantiated in a CDI context using Apache DeltaSpike.