Using JUnit Categories to group tests

JUnit allows to organize tests in groups using Categories. A well-organised​ suit of tests is really important, annotating​ our tests with categories could help to differentiate fast from slow tests or stable from unstable/maturing tests.

Defining Categories
We define our categories creating interfaces

public interface CriticalTests {}
public interface SanityTests {}
public interface FastTests {}
public interface SlowTests {}
public interface StableTests {}
public interface UnstableTests {}

And annotating our test class or individual tests with the Category annotation

public class MyFeatureTest {
	@Test @Category(FastTests.class)
	public void testFast() {
		System.out.println("fast");
	}
	@Test @Category(SlowTests.class)
	public void testSlow() {
		System.out.println("slow");
	}
	@Test @Category({SanityTests.class, SlowTests.class})
	public void testSanity() {
		System.out.println("sanity");
	}
}

Notice, that we can annotate a test with multiple categories.

@Test @Category({SanityTests.class, SlowTests.class})

Run Tests by Category
Configuring the POM
We can use categories from maven configuring properly the version of maven-surefire-plugin and selecting the junit47 provider.

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.17</version>
				<dependencies>
	                <dependency>
	                    <groupId>org.apache.maven.surefire</groupId>
	                    <artifactId>surefire-junit47</artifactId>
	                    <version>2.17</version>
	                </dependency>
	            </dependencies>
			</plugin>

Run tests specifying categories
We can run all the test under a category using the -Dgroups maven attribute. For example run all the fast and stable tests:

mvn test -Dgroups="com.test.groups.FastTests, com.test.groups.StableTests"

That argument could be used in combination with -Dtest to run only a especific test in a test class.

mvn test -Dtest=AppTest.java -Dgroups="com.test.groups.SanityTests"

Run tests with a category profile
The second option is to define maven profiles per category or group of categories. This allows to run maven using a profile

mvn test -PsanityTests

Another advantage of profiles is that allows to combine group selection with file inclusion and exclusion.
Example of profile configurations for multiple categories:

...
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.11</version>
				<dependencies>
	                <dependency>
	                    <groupId>org.apache.maven.surefire</groupId>
	                    <artifactId>surefire-junit47</artifactId>
	                    <version>2.12.2</version>
	                </dependency>
	            </dependencies>
				<configuration>
					<groups>${testcase.groups}</groups>
					<excludes>
                    	<exclude>${exclude.tests}</exclude>
	                </excludes>
    	            <includes>
						<include>${include.tests}</include>
                    </includes>
				</configuration>
			</plugin>
		</plugins>
	</build>
 
	<profiles>
	    <profile>
	        <id>sanityTests</id>
	        <properties>
	            <testcase.groups>com.emc.gs.atlas.ui.categories.CriticalTests</testcase.groups>
				<exclude.tests>**/x/**/*.java</exclude.tests>
	            <include.tests>**/y/**/*.java</include.tests>
	        </properties>
	    </profile>
	    <profile>
	        <id>fastTests</id>
	        <properties>
	            <testcase.groups>com.test.groups.SanityTests</testcase.groups>
	        </properties>
	    </profile>
	    <profile>
	        <id>fastTests</id>
	        <properties>
	            <testcase.groups>com.test.groups.FastTests</testcase.groups>
	        </properties>
	    </profile>
	    <profile>
	        <id>slowTests</id>
	        <properties>
	            <testcase.groups>com.test.groups.SlowTests</testcase.groups>
	        </properties>
	    </profile>
	    <profile>
	        <id>stableTests</id>
	        <properties>
	            <testcase.groups>com.test.groups.StableTests</testcase.groups>
	        </properties>
	    </profile>
	    <profile>
	        <id>unstableTests</id>
	        <properties>
	            <testcase.groups>com.test.groups.UnstableTests</testcase.groups>
	        </properties>
	    </profile>
	</profiles>

Documentation:
Oficial documentation:
https://github.com/junit-team/junit/wiki/Categories
https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html
Other links:
http://java.dzone.com/articles/unit-and-integration-tests
http://www.togsblom.com/2010/04/categorizing-junit-tests.html
https://weblogs.java.net/blog/johnsmart/archive/2010/04/25/grouping-tests-using-junit-categories-0
http://technicaltesting.wordpress.com/2012/09/24/using-junit-category-and-maven-profiles-to-get-stable-test-suites/
http://stackoverflow.com/questions/15648557/maven-unit-tests
http://stackoverflow.com/questions/3100924/how-to-run-junit-tests-by-category-in-maven

Advertisements

Using JUnit Rules

JUnit rules allows the definition of work to be done before and after a test case execution. Than means before either the test execution and also all the @before annotated methods. This facility allows creation of more powerful and cleaner tests. It is a concept similar to JUnitRunners but with the advantage that we can combine multiple rules.

There are a couple of useful rules already implemented in JUnit. For example the TemporaryFolderRule allows creation of files and folders that are guaranteed to be deleted when the test case finishes. A complete rule list is available in https://github.com/junit-team/junit/wiki/Rules.

If we want to create our custom rules we can simply do:

public class MyTestRule implements TestRule {
	public Statement apply(final Statement base, Description description) {
		return new Statement() {
			@Override
			public void evaluate() throws Throwable {
				System.out.println("before");
				try {
					base.evaluate();
				} finally {
					System.out.println("after");
				}
			}
		};
	}
}

And we will use it in our tests via the @Rule annotation.

public class MyTest {
	@Rule
	public MyTestRule myTestRule = new MyTestRule();
 
	@Test
	public void testSanity() throws Exception {
		System.out.println("test execution");
	}
}

Running this test case will print:

before
test execution
after

that proves that the rule interceptor is working as expected.

A real example could be a rule to take snapshoots when a selenium ui tests fails, for example:

public class ScreenshotRule implements TestRule {
	public Statement apply(final Statement base, final Description description) {
		return new Statement() {
			@Override
			public void evaluate() throws Throwable {
				try {
					base.evaluate();
				} catch (Throwable t) {
					takeScreenshot();
					throw t; // Re-throw to allow the failure to be reported to JUnit
				}
			}
			private void takeScreenshot(){
                                WebDriver driver = new FirefoxDriver();
				File imageFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
				String failureImageFileName = "testfailureimage.png";
				File failureImageFile = new File(failureImageFileName);
				FileUtils.moveFile(imageFile, failureImageFile);
			}
		};
	}
}
public class MySeleniumTest {
	@Rule
	public ScreenshotRule screenshotRule = new ScreenshotRule();
 
	@Test
	public void testThatFails() {
		WebDriver driver = new FirefoxDriver();
		driver.get("http://www.google.com");
		driver.findElement(By.id("non_existing_element"));
	}
}

Using rules we can reduce the boilerplate code in our tests, it’s especially useful for Integration Tests or Automation Tests that usually share a complex context or environment set up previous the test execution.

Other interesting use cases of rules are to use them as a Runners replacement, when we want to combine more than one Runner. You can see an example for SpringJUnit4ClassRunner or MockitoJUnitRunner in http://www.alexecollins.com/content/tutorial-junit-rule/

An other interesting point is to combine Rules with custom annotations.

Ordering Rules
We must be careful using multiple rules because the order of excution is not assured by default. To illustrate that problem we can use the next custom rule:

public class LoggingRule implements TestRule {
	private String name;
	public LoggingRule(String name) {
		this.name = name;
	}
	public Statement apply(final Statement base, Description description) {
		return new Statement() {
			@Override
			public void evaluate() throws Throwable {
				try {
					System.out.println("starting " + name);
					base.evaluate();
				} finally {
					System.out.println("finished " + name);
				}
			}
		};
	}
}

And create a little test with three rules.

public class RulesOrderTest {
	
	@Rule public LoggingRule rule1 = new LoggingRule("rule 1");
	@Rule public LoggingRule rule2 = new LoggingRule("rule 2");
	@Rule public LoggingRule rule3 = new LoggingRule("rule 3");

	@Test
	public void test() {
	}
}

Running this test case will print:

starting rule 3
starting rule 2
starting rule 1
finished rule 1
finished rule 2
finished rule 3

But that order could be different if we execute it in other java VM.
If we want to assure the ordering of the rules execution we should use the RuleChain test rule. The order in the chain will be the order of the rules execution.

public class RulesOrderTest {
		
	@Rule 
	public TestRule chain = RuleChain
                           .outerRule(new LoggingRule("outer rule"))
                           .around(new LoggingRule("middle rule"))
                           .around(new LoggingRule("inner rule"));
	@Test
	public void test() {
	}
}

Now it will print:

starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule

Documentation:
https://github.com/junit-team/junit/wiki/Rules
http://www.alexecollins.com/content/tutorial-junit-rule/
http://www.codeaffine.com/2012/09/24/junit-rules/
http://junit.org/javadoc/latest/org/junit/rules/RuleChain.html

Maven – Adjuntar los sources de un artefacto

En el building de un proyecto java, por ejemplo una libreria jar, queremos que Maven prepare también un artefacto con los fuentes del código. De esta forma, un proyecto de ejemplo milibreria, tendria tras el building los artefactos milibreria.jar y milibreria-sources.jar.

Para ello se utiliza el plugin sources, el cual podemos invocar directamente con el comando:
mvn source:jar

O podemos configurarlo en nuestro pom como un plugin del building:

    <build>
      <plugins>
	<plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-source-plugin</artifactId>
	  	<executions>
	    	<execution>
	      		<id>attach-sources</id>
	      		<goals>
	        	  <goal>jar</goal>
	      		</goals>
	    	</execution>
	  	</executions>
	</plugin>
      <build>
    <plugins>

Documentación:
http://maven.apache.org/plugin-developers/cookbook/attach-source-javadoc-artifacts.html

FlexJson – Incluir o excluir campos a serializar.

La clase JSONSerializer de la libreria FlexJson permite serializar objetos Java a su representación JSon. Es importante hacer uso de las exclusiones e inclusiones, para evitar parsear campos que no necesitamos enviar a la capa de interfaz. O para controlar y evitar posibles errores de parseo en objetos con relaciones circulares.

Como ejemplo, para el parseo de un objeto ConsultaPermiso con objetos agregados Consulta y Usuario, quiero excluir todos los campos de dichos objetos agregados, e incluir de estos solo los campos: consulta.id, usuario.id y usuario.nombre.

public class ConsultaPermiso {

    @ManyToOne
    private Consulta consulta;

    @ManyToOne
    private Usuario usuario;

    @Enumerated
    private TipoPermiso permiso;
    
    public static String toJsonArray(Collection<ConsultaPermiso> collection) {
        return new JSONSerializer().exclude("*.class").include("consulta.id", "usuario.id", "usuario.nombre").exclude("consulta.*", "usuario.*").serialize(collection);
    }
...

Un ejemplo del JSon resultante sería:

[{"id":100, "consulta":{"id":200}, "permiso":"VER", "usuario":{"id":"1","nombre":"User1"}, "version":0}]

Solucionando problema Encoding UTF-8 en Java Webapp sobre Tomcat 6

Trabajando en un proyecto Eclipse WTP Tomcat6, de una aplicación web Java con controladores basados en Spring de este estilo:

    @RequestMapping(params = "find=ByUserName", headers = "Accept=application/json")
    @ResponseBody
    public ResponseEntity<String> jsonFindUsuarioByUserName(@RequestParam("userName") String userName) {
... }

Donde la codificación utilizada es UTF-8. Teniendo correctamente definidos el content-type de paginas html y jsp, así como haciendo uso del CharacterEncodingFilter Spring en el web.xml.

  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>

me he encontrado con un problema en la codificación de los parámetros de la request URI no llegan al método del controller en UTF-8.

Después de perder un buen rato buscando y probando diferentes soluciones, he encontrado que el problema se encuentra en la configuración del conector de Tomcat. Para solucionarlo hay que añadir la propiedad URIEncoding=”UTF-8″ a la configuración del conector en el fichero server.xml.

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8" />

Si utilizamos Tomcat desde Eclipse, el fichero a editar se encuentra en Servers/apache-tomcat-X.X.X-conf/server.xml

tomcat6_utf8_problem

Apendice I – Definir URIEncoding en Jboss AS 7.1
La configuración del URIEncoding para un servidor Jboss AS 7.1 se realiza de modo distinto a Tomcat. En concreto definiendo 2 propiedades en la configuración de la instancia.
En una configuración básica de Jboss basada en standalone, añadimos estas lineas al fichero de configuración standalone.xml, debajo de la sección extensions.

<system-properties>
	<property name="org.apache.catalina.connector.URI_ENCODING" value="UTF-8"/>
	<property name="org.apache.catalina.connector.USE_BODY_ENCODING_FOR_QUERY_STRING" value="true"/>
</system-properties>

Documentación:
http://tomcat.apache.org/tomcat-6.0-doc/config/http.html#Attributes
http://stackoverflow.com/questions/138948/how-to-get-utf-8-working-in-java-webapps
http://jboss7-oracle.blogspot.com.es/2011/12/uriencoding-in-jboss7.html

Integrando Sonar en Eclipse

Sonar es una herramienta fantástica para medir y asegurar la calidad en proyectos Java, habitualmente utilizamos Sonar dentro del ciclo de integración continua con Jenkins y revisamos los resultados y análisis de código a través de la web del servidor Sonar.

Mediante el plugin Sonar para eclipse, podemos integrar mucho mas Sonar con el desarrollo. Y consultar desde dentro de eclipse las metricas, violaciones de reglas, etc.

Intalación
El plugin de Sonar para eclipse esta disponible desde el marketplace, por lo tanto la instalanción es tan secilla como abrir el marketplace (Help > Eclipse Marketplace), buscar ‘sonar plugin’, e instalar.

sonar_eclipse_01
Una vez instalada abrimos las diferentes vistas del nuevo plugin, por ejemplo la vista Violations, desde (Windows -> Show View -> Other -> Sonar).

Configurar servidor Sonar
Desde (Windows -> Preferences -> Sonar) podemos configurar los servidores de Sonar que queramos utilizar. Por defecto viene configurada una ruta a un servidor sonar local en el puerto 9000. Aquí añadiriamos la ruta al servidor Sonar de nuestro equipo.
sonar_eclipse_02

Configurar proyecto
Por último tenemos que asociar cada uno de los proyectos del workspace para los que queramos utilizar el plugin Sonar.
Para ello con el boton derecho sobre el proyecto accedemos a (Sonar -> Associate with Sonar). Tenemos que indicar de forma manual el GroupId y ArtifactId de nuestro proyecto.
sonar_eclipse_03

Como ejemplo de las posibilidades del plugin, podemos ver como desde la vista ‘Violations’ tenemos un listado con todas las violaciones de reglas sonar. Tenemos la posibilidad de visualizarlas para todo el proyecto o únicamente para la clase actual.
sonar_eclipse_04

Desde la vista ‘Web’ de Sonar se visualiza la web de Sonar para la clase actual, estoy es muy util por ejemplo para comprobar la cobertura de una clase.
sonar_eclipse_05

Las vistas de ‘Hotspots’ y ‘Measures’, también pueden sernos de utilidad
sonar_eclipse_06

Documentación:
– Sonar Code Quality Testing Essential, Packtpub.
http://docs.codehaus.org/display/SONAR/Using+Sonar+in+Eclipse

Importar librerias JS como web resources Spring.

Spring MVC permite mapear las peticiones a una determinada ruta URL, hacia contenidos estáticos (JS, CSS, imagenes, …) que se encuentren en otra localización como el classpath, otro servidor, etc. Esto se consigue mediante la anotación del fichero webmvc-config.xml.

<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources -->
<mvc:resources location="/, classpath:/META-INF/web-resources/" mapping="/resources/**"/>

Conociendo lo anterior podemos poner en juego una buena práctica, que consiste en empaquetar en un .jar las librerias JS que utilize nuestra aplicación, por ejemplo el framework JS Dojo. Y publicarlas como recurso web con Spring. De esta forma no tenemos que incluir en el código fuente de nuestra aplicación dichas librerias (con miles de ficheros .js). Lo que a la vez supone tener que versionar esos ficheros en nuestro SVN, dificulta el cambio de version de la libreria en cuestión, etc.

Como ejemplo creamos la libreria dojo-js-resources-1.7.1.jar con la estructura:
/META-INF/web-resources/
/dijit/
/dojo/
/dojox/

y la publico en mi repositorio maven. Podemos añadirla a cualquier proyecto con esta dependencia maven:

<dependency>
  <groupId>com.mylibs.dojo</groupId>
  <artifactId>dojo-js-resources</artifactId>
  <version>1.7.1</version>
</dependency>

lo que hará que este disponible en nuestro classpath, y que spring la publique en resources. Una URL de ejemplo sería: http://localhost:8080/myapp/resources/dojo/dojo.js