Selenium Liferay Junit

Selenium Liferay Junit

Selenium Liferay Junit

Esta entrada titulada Selenium Liferay JUnit, está dedicada al uso de Selenium en Liferay. Tanto para la realización de pruebas de integración, como para la invocación de servicios unitarios mediante el uso de reflexión. Para llevar a cabo la invocación utilizaremos un formulario común para cualquier servicio que necesitemos probar.

Para ejecutar las pruebas nos valdremos de JUnit. En caso de que alguien desconozca su uso, hace ya algún tiempo dedique una entrada a las pruebas de software, titulada Liferay JUnit. Si queréis conocer algo más sobre el tema os recomiendo su lectura.

Entorno de desarrollo

Para la realización de esta entrada, se han utilizado las siguientes herramientas e IDE’s:

  • Eclipse Luna Release (4.4.0).
  • Liferay SDK 6.2.0
  • Liferay 6.2 CE GA5 bundled with Tomcat.
  • Junit 4 / Selenium Java 2.53.

En principio cualquier versión de Eclipse o Spring Tool Suite compatible con el SDK es igualmente válida, al igual que cualquier versión 6.2 de Liferay CE. Si alguien tiene dudas referentes a la configuración del entorno, puedes ver la siguiente entrada Liferay Spring Tool Suite sencillo de configurar.

Estructura del proyecto

Mi recomendación es que bajéis el proyecto de GitLab. De una forma u otra el tipo de proyecto creado, o que se debe crear es de tipo Portlet. La estructura del proyecto para llevar a cabo las pruebas, puede verse en la siguiente imagen.

Estructura proyecto

En la carpeta “test/integration” se ubicarán los test de integración. Además debemos añadir al build path la carpeta como se puede ver en la imagen siguiente. Para ello y en primer lugar hacemos clic derecho sobre el proyecto, seleccionamos “Java Build Path”, a continuación seleccionamos la carpeta y finalmente pulsamos “OK”.

Build path

Para descargar las librerías de Selenium, se ha decidido utilizar Maven. Maven es una herramienta de gestión y construcción de proyectos Java. En el fichero de configuración “pom.xml” se encuentran las dependencias de Selenium. Si no se quiere utilizar, siempre existe la posibilidad de descargar  las librerías manualmente o utilizar alguna otra herramienta como Ivy o Gradle.

Construcción del portlet de prueba

En este apartado describiremos el contenido del portlet de prueba. Este portlet está compuesto de un formulario, que nos permite probar de manera unitaria cualquier servicio de Liferay o cualquiera que tengamos creado en otro proyecto. El único requisito para poder probar servicios ubicados en otro proyecto, es tener definida una dependencia al mismo en el fichero “liferay-plugin-package.properties” del proyecto que ejecuta las pruebas.

El formulario está compuesto de tres elementos “input”. Cada uno de los cuales sirve para:

  • Nombre de la clase Util: Nombre completo de la clase en la que se encuentra el servicio. Un ejemplo sería “com.liferay.portal.service.UserLocalServiceUtil”.
  • Nombre del método: Nombre del método que vamos a probar, por ejemplo “fetchUser”.
  • Lista de parámetros: Listado de parámetros separados por comas y sin espacios. En nuestro caso sería “20801”.

Además del formulario se creará una sección para la visualización del resultado de la llamada. Es decir, mostraremos el tipo de dato devuelto ya sea un objeto o dato primitivo, y el valor del mismo. Tal y como se puede ver en la siguiente imagen.

Formulario

Una vez explicada la vista del portlet, es necesario entender cómo funciona el controlador Java encargado de manejar el “action” del formulario. El primer paso consiste en recoger los datos enviados a través del propio formulario.

String method = ParamUtil.getString(actionRequest, "method");

String[] params = ParamUtil.getParameterValues(actionRequest, «params»); String service = ParamUtil.getString(actionRequest, «service»);

El siguiente paso consiste en instanciar el servicio, obtener sus métodos. Además, declaramos una lista de objetos donde almacenar los parámetros de este método.

Class<?> serviceUtilClass = Class.forName(service);
Object serviceUtilInstance = serviceUtilClass.newInstance();
Method[] methods = serviceUtilClass.getMethods();
List<Object> parameters = new ArrayList<Object>();

A continuación recorremos la lista de métodos hasta encontrar aquel que queremos invocar. Dado que Java permite la sobrecarga de métodos, debemos comprobar tanto el nombre como su número de parámetros.

for (Method m : methods) {
     if( m.getName().equals(method) && Validator.equals(m.getParameterTypes().length, params.length) ){
          …
     }
}

Ahora que hemos encontrado dicho método, obtendremos sus parámetros y tipos. Para cada uno de ellos realizamos un cast usando la clase GetterUtil de Liferay, y los guardaremos en la lista de objetos declarada anteriormente.

Class<?>[] types = m.getParameterTypes();
for (int i = 0; i < types.length; i++) {
     if ( types[i].equals(Long.class) || types[i].equals(long.class) ){
          parameters.add(GetterUtil.getLong(params[i]));
     }else if( types[i].equals(String.class) ){
          parameters.add(GetterUtil.getString(params[i]));
     }
          ...
 
}

En último lugar, invocamos el método correspondiente en función del número de parámetros que tiene definidos. Guardamos los resultados en la render para que puedan ser mostrados por la vista del portlet.

switch (params.length) { 
     case 0: 
           setResult(getMethod().invoke(serviceUtilInstance)); 
           break; 
     case 1: 
           setResult(getMethod().invoke(serviceUtilInstance, parameters.get(0))); 
           break; 
     default: 
           break; 
} 
actionResponse.setRenderParameter("result", getResult().toString()); 
actionResponse.setRenderParameter("type", getMethod().getReturnType().getName());

Selenium

El objetivo de este apartado es contar brevemente que es Selenium y para qué sirve. Todo aquel que ya lo conozca puede saltarse este punto si lo desea.

Selenium es un entorno de pruebas software para aplicaciones web. Es un software de código abierto bajo licencia apache 2.0. Selenium está compuesto del siguiente conjunto de herramientas:

  • Selenium IDE: Es una extensión de Firefox, que permite grabar, editar y depurar pruebas. Al grabar una serie de acciones sobre el navegador, la extensión genera automáticamente scripts en Selenese, un lenguaje de scripting.
  • Selenium Client API: Alternativa a Selenese, que permite escribir las pruebas en varios lenguajes de programación, Java, Python…
  • Selenium WebDriver: Permite la utilización de comandos enviados tanto en Selenese, como vía API al navegador. Se implementa a través de un controlador específico para cada navegador llamado WebDriver. Este controlador inicia una instancia del navegador, gestionando tanto el envío como la recepción de información.
  • Selenium Grid: Servidor que permite usar instancias de navegadores en máquinas remotas. Permite ejecutar pruebas en paralelo en múltiples máquinas y manejar diferentes versiones y configuraciones de manera centralizada.

Si queréis más información acerca de Selenium, en el apartado de referencias podéis encontrar un par de enlaces, o bien ir directamente a su página oficial haciendo clic aquí.

Casos de prueba

Como es lógico en una entrada sobre pruebas, he dedicado un apartado a los casos de prueba. Para probar la funcionalidad de Selenium, he realizado dos casos de prueba. El primero realiza el proceso de autenticación en la plataforma y el segundo hace uso del formulario creado anteriormente para probar un servicio del portal de Liferay.

Con el objetivo de organizar el diseño de las pruebas y facilitar su comprensión, se ha creado un fichero de configuración y una clase de constantes. El fichero de configuración muy originalmente llamado “config.properties”, se utiliza para almacenar los datos necesarios para la autenticación de usuario, así como el dominio donde está ubicado nuestro Liferay.

user=prueba@prueba.com
pass=prueba
domain=http://localhost:8080

Por otro lado en la clase “Constant.java” se han declarado todos los elementos del DOM que necesitamos para realizar las pruebas. La clase de Selenium que permite obtener dichos elementos se llama “By.java”. Esta clase ofrece diferentes métodos, en mi caso únicamente he utilizado los métodos “name”, “id” y “className”. A continuación se muestra un ejemplo de cada uno de ellos.

public static final By DOM_FORM_FM = By.name("_seleniumtest_WAR_seleniumtestportlet_fm");
public static final By DOM_LOGIN_FORM = By.id("_58_fm");
public static final By DOM_ALERT_ERROR = By.className("alert-error");

Para realizar las pruebas he utilizado WebDriver. Para que este WebDriver funcione correctamente  es necesario configurar algunos aspectos, tales como el sistema operativo, el navegador y la versión.

Se creará una nueva instancia del navegador por cada caso de prueba. Además se carga el fichero de configuración en una Map de Java. La última línea establece el tiempo de espera.

@Before
public void setUp() throws Exception {
    DesiredCapabilities capabilities = DesiredCapabilities.firefox();
    capabilities.setCapability("platform", Platform.WINDOWS);
    capabilities.setCapability("version", "46");
    capabilities.setCapability("browserName", "firefox");
    InputStream input = IntegrationTest.class.getClassLoader().getResourceAsStream("config.properties");
    prop.load(input);
    driver = new FirefoxDriver(capabilities);
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}

Al finalizar cada caso de prueba la instancia del navegador se cerrará.

@After
public void tearDown() throws Exception {
     driver.quit();
}

Autenticación

El primero de los casos de prueba creados, consiste como ya se ha mencionado en realizar el proceso de autenticación en Liferay. Para ello en primer lugar navegamos a la url correspondiente. Una vez en dicha url, debemos rellenar los elementos input del formulario. Los datos se obtienen de la Map cargada con los datos del fichero de configuración. El siguiente paso consiste en hacer submit del formulario y esperar el resultado de la operación. Gracias a JUnit podemos comprobar mediante el método “assertEquals” si el proceso ha devuelto errores.

@Test
public void doLogin() throws Exception {
     driver.get(prop.getProperty("domain")+"/c/portal/login");
     WebElement name = driver.findElement(Constant.DOM_LOGIN_NAME);
     name.clear();
     name.sendKeys(prop.getProperty("user"));
          ...
     WebElement form = driver.findElement(Constant.DOM_LOGIN_FORM);
     form.submit();
     List<WebElement> msgsError = driver.findElements(Constant.DOM_ALERT_ERROR);
     assertEquals(0, msgsError.size());
}

Servicio unitario

El proceso del segundo caso de prueba es similar al del caso anterior. Sin embargo tiene la peculiaridad, de que los datos que se utilizan en cada uno de los inputs, se introducen a partir de una cadena.

@Test
public void fecthUser() throws Exception {
     driver.get(prop.getProperty("domain"));
     WebElement service = driver.findElement(Constant.DOM_FORM_SERVICE);
     service.clear();
     service.sendKeys("com.liferay.portal.service.UserLocalServiceUtil");
          ...
     List<WebElement> msgsSuccess = driver.findElements(Constant.DOM_ALERT_SUCCESS);
     assertEquals(1, msgsSuccess.size());
}

Ejecución y resultados

Para lanzar la ejecución de las pruebas basta con hacer clic derecho sobre el proyecto y  seleccionar “Liferay/ test”. Los resultados de la ejecución se mostrarán en la consola de JUnit tal y como se ve en la siguiente imagen.

Resutado consola

Otra opción es hacer doble clic en el fichero “test-results/unit/TEST-….IntegrationTest.xml”. Se nos abrirá la vista de JUnit en nuestro IDE tal y como se muestra a continuación.

Resutado en vista

Código fuente

El código fuente de ejemplo se puede descargar desde Gitlab siguiendo el siguiente enlace.

https://gitlab.com/omaikyto/selenium-test-portlet

Referencias

Selenium

https://es.wikipedia.org/wiki/Selenium

http://toolsqa.com/selenium-webdriver/selenium-introduction/

https://www.airpair.com/selenium/posts/selenium-tutorial-with-java

JUnit

https://es.testingbot.com/support/getting-started/junit.html

Reflection

http://www.arumeinformatica.es/blog/java-reflection-parte-1/

Tienes que estar conectado para dejar un comentario.