domingo, 25 de julio de 2010

Links del día: Mocks, Building tools

"Untestable" code - JMockit: bastante más fácil que con Surrogate. Hace falta Java 5 porque hace uso de la instrumentalización.

Gradle: Why? : Parece que Hibernate se pasa a Gradle como herramienta de construcción del proyecto. ¿Hora de cambiar?

viernes, 9 de julio de 2010

Sobreescribir métodos estáticos para testeo en Maven 2 usando Surrogate.

Creo que en inglés me habría quedado un título más correcto. Algo así como: 'Mocking static methods for testing in Maven 2 using Surrogate'.

El problema
El caso es que me encuentro con que la clase que quiero testear llama al método estático OpenCms.getRoleManager(). Además, el proyecto se construye con Maven 2 (ó 3), por lo que habrá que modificar el POM consiguientemente.

Esta es la clase:

package arm.opencms.accesscontrol;
import org.opencms.file.CmsObject;
import org.opencms.main.OpenCms;
import org.opencms.security.CmsRole; 

public class XmlContentAccessControl {

  private CmsRole ACCEPTED_ROLE=CmsRole.VFS_MANAGER;
  public boolean hasPermission(CmsObject cmsObject) {

    return OpenCms.getRoleManager.hasRole(cmsObject,ROLE);

  }
}

La solución más cabal: refactorizar

En lugar de adaptar nuestro código de prueba, podemos adaptar nuestro código principal para que sea más testeable. En este caso podemos declarar un atributo de la clase para almacenar un CmsRoleManager:

package arm.opencms.accesscontrol;
import org.opencms.file.CmsObject;
import org.opencms.security.CmsRoleManager;
import org.opencms.security.CmsRole; 

public class XmlContentAccessControl2 {

  private CmsRoleManager roleManager;   
    
  public XmlContentAccessControl(CmsRoleManager roleManager){
    this.roleManager=roleManager;
  }

  private CmsRole ACCEPTED_ROLE=CmsRole.VFS_MANAGER;
  public boolean hasPermission(CmsObject cmsObject) {

    return this.roleManager.hasRole(cmsObject,ROLE);

  }
}


Si refactorizar no es posible o deseable, una posible solución: Surrogate

Si la única salida es llamar al método estático, podemos usar el framework Surrogate, que, apoyándose en AspectJ, permite definir sustituciones de los métodos o de las clases principales en nuestro código de prueba. Una de sus funcionalidades es la de sobreescribir métodos estáticos.

Para nuestro ejemplo, usaremos el siguiente árbol de directorios con sus correspondientes contenidos:

/
|-src
| |-main
| | |-java
| | | |-arm/opencms/accesscontrol
| | |   |-XmlContentAccessControl.java
| | |-aspect
| |   |-OpenCmsStaticCalls.aj
| |-test
|   |-java
|     -arm/opencms/accesscontrol
|      |-TestAccessControl.java
|-test
|  |-lib
|    |-surrogate-core-1.0rc1.jar
|-pom.xml

Y el contenido de los ficheros:

pom.xml

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelversion>4.0.0</modelversion>
 <groupid>arm.opencms</groupid>
 <artifactid>arm.opencms.accesscontrol</artifactid>
 <name>AccessControl</name>

 <dependencies>
  <dependency>
   <groupid>org.opencms</groupid>
   <artifactid>opencms</artifactid>
   <version>7.5.2</version>
  </dependency>
  
  <dependency>
   <groupid>junit</groupid>
   <artifactid>junit</artifactid>
   <version>4.8.1</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupid>org.jmock</groupid>
   <artifactid>jmock-junit4</artifactid>
   <version>2.5.1</version>
   <scope>test</scope>
  </dependency>
  
  <dependency>
   <groupid>net.sourceforge.surrogate</groupid>
   <artifactid>surrogate-core</artifactid>
   <version>1.0rc1</version>
   <scope>test</scope>  
  </dependency>
  <dependency>
     <groupid>org.aspectj</groupid>
     <artifactid>aspectjtools</artifactid>
     <version>1.6.7</version>
     <scope>test</scope>
  </dependency>
  <dependency>
   <groupid>org.aspectj</groupid>
   <artifactid>aspectjrt</artifactid>
   <version>1.6.7</version>
   
  </dependency>  
  <dependency>
   <groupid>mockobjects</groupid>
   <artifactid>mockobjects-core</artifactid>
   <version>0.09</version>
   <scope>test</scope>
  </dependency>  
 </dependencies> 
 <build>
 <plugins>
        <plugin>
            
            <artifactid>maven-install-plugin</artifactid>               
            <executions>
                <execution>
                    <id>install-javabridge-javabridge</id>
                    <phase>initialize</phase>
                    <goals>
                        <goal>install-file</goal>
                    </goals>
                    <configuration>
                        <file>test/lib/surrogate-core-1.0rc1.jar</file>
                        <groupid>net.sourceforge.surrogate</groupid>
                        <artifactid>surrogate-core</artifactid>
                        <packaging>jar</packaging>
                        <version>1.0rc1</version>
                    </configuration>
                </execution>
            </executions>
        </plugin>
 <plugin>
           <groupid>org.codehaus.mojo</groupid>
           <artifactid>aspectj-maven-plugin</artifactid>
           <version>1.3</version>
           <configuration>
  <compliancelevel>1.5</compliancelevel>
      <aspectdirectory>src/test/aspect</aspectdirectory>
    </configuration>
           <executions>
              <execution>
                 <goals>
                   <goal>compile</goal>
                 </goals>
              </execution>
           </executions>
        </plugin>           
    </plugins> 
  </build>
</project>

La biblioteca Surrogate no está disponible en ningún repositorio público, por lo que la instalamos durante la inicialización como vimos en un post anterior. También se usa el plugin de AspectJ, para compilar el aspecto OpenCmsStaticCalls.aj .


TestAccessControl.java

@RunWith(JMock.class)
public class XmlContentAccessControlTest {
        
    private Mockery context = new JUnit4Mockery() {{
 setImposteriser(ClassImposteriser.INSTANCE);
    }};

    CmsObject mockCmsObject=context.mock(CmsObject.class);
    CmsRoleManager mockRoleManager=context.mock(CmsRoleManager.class);
    
    @Test
    public void testHasPermissionOnTab()throws NoSuchMethodException, CmsRoleViolationException {

 SurrogateManager mm = SurrogateManager.getInstance();
 mm.reset();
 //OpenCms.getRoleManager() -> mockRoleManager
 MockMethod mockGetRoleManager = mm.addMockMethod(new MockMethod(OpenCms.class, "getRoleManager"));
 mockGetRoleManager.addReturnValue(mockRoleManager);
 
 context.checking(new Expectations() {{

     allowing(mockRoleManager).hasRole(with(is(mockCmsObject)),
                                (CmsRole)with(allOf(an(CmsRole.class),hasProperty("roleName", is("VFS_MANAGER")))));
      will(returnValue(true));
 }});
 
 XmlContentAccessControl accessControl=new XmlContentAccessControl();
 
 assertTrue(accessControl.hasPermission(mockCmsObject));
    }


OpenCmsStaticCalls.aj

aspect OpenCmsStaticCalls extends net.sf.surrogate.core.SurrogateCalls {
 /**
  * Implementation of the mock pointcut
   */
 protected pointcut mockPointcut() :
 (
  call(* org.opencms.main.OpenCms.*(..))
    );                             
} 

lunes, 5 de julio de 2010

Torneo de Kayak-Polo Internacional de Horb 2010

El 3 de julio se celebró el Torneo de Kayak-Polo Internacional de Horb, en la ciudad de Horb am Neckar. Participaron 6 equipos masculinos y una cifra similar de equipos infantiles y cadete. El ganador fue el KSC Mannheim.

Como se puede observar en la marca de agua, he robado la foto vilmente de www.kanupolo-villingen.de.