Setting up Cucumber-jvm

Cucumber JVM is Java implementation of Cucumber BDD.

Integrating into the Project

The installation using maven is super simple, just add the dependency and you are ready to go. Make sure you add both command line interface (cucumber-core) and the IDE interface (cucumber-junit)

I was using Intellij and add Intellij Cucumber plugin, to make the navigations easier.

One thing i liked very much is the ability to add custom annotations to the feature. You can add a custom annotation and can create Before and After hook for them.

In .feature file

@Email
Feature:

In the step definitions file.

@Before({"@Email"})
@After({"@Email"})

Integrating with Spring

For Spring integration you need to add one more component of the cucumber-jvm (cucumber-spring)

It is advisable to have a test runner class which can run all the feature files in one go especially when you are runnning in the CI.

The structure of the test runner class will be :

@RunWith(Cucumber.class)
public class CucumberAdapterTest {
}

Make sure to place all the feature files in the same package as of this Runner class. Or you can specify the path using the cucumber options, like this.

@RunWith(Cucumber.class)
@Cucumber.Options(features = "classpath:**/*.feature")
public class CucumberAdapterTest {
}

If you are placing all the step definition in other package you can add that to the annotation using glue attribute.

@RunWith(Cucumber.class)
@Cucumber.Options(features = "classpath:**/*", glue = {"path of the step definitions"})
public class CucumberAdapterTest {
}

This will look up for cucumber.xml file in the classpath. This xml file can hold all the bean definitions. My cucumber.xml was super simple.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <import resource="classpath*:/application-context.xml"/>

    <context:component-scan base-package="path of the step definition"/>
    <context:annotation-config/>
</beans>

The step defnitions can lie in a different package and make sure you use glue attribute to wire them in the Runner class.

public class StepDefinitions {

@Autowired
EntityRepository entityRepository;

@Given("^Register a user$")
public void registerUser() throws Throwable {

}
}

Integrating with Spring Transactions

One last thing that i wanted to do is to hook up Spring transactions. So all the data created by the features have to be removed after the test completes. So you can write independent tests without bothering about the data.

You can use ‘txn‘ annotation that comes with Cucumber-JVM. All you need to do is to wire up that package along with your adapter class.

@RunWith(Cucumber.class)
@Cucumber.Options(glue = {"cucumber.api.spring"})
public class CucumberAdapterTest {
}

and

@txn
Scenario: Some scenario to test

 

Hamcrest conflict in jUnit.

Using jUnit 4.8 i got into an issue when testing the few lambda expressions. I was constantly getting this error while testing code involving Hamcrest matchers.

java.lang.NoSuchMethodError: org.hamcrest.core.AllOf.allOf(Lorg/hamcrest/Matcher;Lorg/hamcrest/Matcher;)Lorg/hamcrest/Matcher;

However when i ran the application it was all fine. So i could sense the issue with the jUnit.

The problem is due to hamcrest versioning issue with jUnit. jUnit uses an old version while other libraries (in my case LambdaJ) was using the latest version.
The fix will be to download the junit-dep-4.*.jar from the jUnit download page. Since you app already have Hamcrest class the test will run smoothly.

Handle MaxUploadSizeExceededException in Spring

I was doing a AJAX file upload using jQuery and Spring 3. Spring provides a way to limit the file being uploaded and this can be configured while creating the multipart bean by specifying the maxUploadSize parameter.

So whenever an user tries to upload a file with size size greater than that of the specified one then Spring will throw ‘MaxUploadSizeExceededException’ exception and returns back. The problem for me is that i was doing the file upload using AJAX so i wanted a custom error to be thrown rather than the Spring’s default error.

And also because of this exception the control will not even reach your specified controller so there is no chance to catch it in your Controller. After some lookup i found this simple fix for it.

FileUploadController: Controller which will handle the file upload request.

Make this FileUploadController to implement HandlerExceptionResolver. This will force you to define resolveException() method.

    @ResponseBody
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        if (e instanceof MaxUploadSizeExceededException) {
            ModelAndView modelAndView = new ModelAndView("inline-error");
            modelAndView.addObject("error", "Error: Your file size is too large to upload. Please upload a file of size < 5MB and continue.");
            return modelAndView;
        }
        e.printStackTrace();
        return new ModelAndView("500");
    }

 How to show the error on the same page:

The call to the controller is from a jQuery ajax method. But the problem here is that even with this approach your jQuery POST method is going to receive a HTTP_OK message from the controller. Hence if you are waiting at the error callback then you have no chance of catching this error.

So what i have done here is to return inline-error view back as the response. On the success callback of the jQuery i check for the presence of the error_div in the response and display the field in the page. Else show the success message.

inline-error.jsp

<div class="error" id="error_div">${error}</div>

PS: This is definitely not the cleanest approach, but this solved my problem :)

Writing Custom Tags for JSTLs

First start with writing a tag library descriptor(TLD). A TLD is a XML document that contains information about a library as a whole and about each tag contained in the library.
The structure of the TLD file is pretty readalbe.

Below is an implementation of tag which takes in a section name(value) of a web page and checks whether the logged-in user has rights to view the section.

Step 1: custom.tld

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
        "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib xmlns="http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
    <tlibversion>1.0</tlibversion>
    <jspversion>1.1</jspversion>
    <shortname>custom</shortname>
    <info>Custom tag library</info>
    <tag>
        <name>permission</name>
        <tagclass>com.prasans.PermissionTag</tagclass>
        <info>
            Checks the User Permission to access the content.
        </info>
        <attribute>
            <name>value</name>
            <required>true</required>
        </attribute>
        <attribute>
            <name>invertCondition</name>
            <required>false</required>
        </attribute>
    </tag>
</taglib>

Here we have implemented a tag called permission within the ‘custom’ tag library.

Usage: <custom:permission value=”">{section}</custom:permission>
Similarly you can add more tags to your library by adding more <tag> nodes.

After done with defining TLD, next step is to implement the conditional logic. Below is a piece of Java code that does the implementation of the TLD.

Step 2: PermissionTag.java

package com.prasans;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.jstl.core.ConditionalTagSupport;

public class PermissionTag extends ConditionalTagSupport {
    private String value = null;
    private boolean invertCondition;

    public void setValue(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public boolean isInvertCondition() {
        return invertCondition;
    }

    public void setInvertCondition(boolean invertCondition) {
        this.invertCondition = invertCondition;
    }

    @Override
    protected boolean condition() {
        // If needed you can access Request Object like this.
        HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
        boolean permission = checkForThePermission(value);
        return invertCondition ? !permission : permission;
    }
}

Explanation:

* Since the expectation of this tag is to return true or false, we are extending the ConditionalTagSupport class. Based on the need you can choose upon your class implementation.

*Note that all tag attributes are member variables of the class and all of them should have getters and setters.

*Here we have overridden the condition() from ConditionalTagSupport to return the needed boolean result.

* InvertCondition is an attribute that helps us in simulating negative scenarios.

For ex: “Show the section If  User A do not have ‘X’ permission ”

After building the TLD and its corresponding logic, the next step is to integrate with your application.
Add the custome tag library to your web.xml to integrate with your web app.

Step 3: web.xml

<jsp-config>
    <taglib>
        <taglib-uri>/custom</taglib-uri>
        <taglib-location>/WEB-INF/tags/custom.tld</taglib-location>
    </taglib>
</jsp-config>

The taglib-uri is the <shortname> defined in the TLD file. And <taglib-location> is the location of the tld. Make sure that you are bundling the TLD along with your WAR.

Thats it. You can start using your custom tags in your JSPs now.

Reloading an activity in Android

More often i wanted to reload an activity to refresh the contents of an page. I have seen many ways to do this in Android world and i always puzzled about the best approach.
However these are some of the approaches that i took . I found the following two approaches a lot cleaner as they kill the existing intent and restart.
Approach 1:
Intent intent = getIntent();
finish();
startActivity(intent);
Approach 2:
Intent intent = getIntent();
overridePendingTransition(0, 0);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
overridePendingTransition(0, 0);
startActivity(intent);
Note: The second approach works only from API 5+