Testing en Spring Boot con JUnit 4\5. Mockito, MockMvc, REST Assured, bases de datos embebidas.

logo springEn el tutorial Introducción a Spring Boot: Aplicación Web con servicios REST y Spring Data JPA se construye una pequeña aplicación web que muestra en pantalla los registros de una tabla de una base de datos MySQL a la que se accede a través de Spring Data JPA, y que también dispone de una pequeña api REST. Sin embargo, falta un elemento vital como son los tests. Para suplir esta carencia, en el presente tutorial voy a mostrar cómo configurar tests de integración en Spring Boot utilizando esa misma aplicación así como algunas opciones y librerías que pueden ser de gran ayuda. Los tests se desarrollarán con JUnit 4 pero al final del tutorial veremos cómo utilizar también JUnit 5.

El siguiente diagrama de clases UML proporciona una vista general de la estructura de la aplicación a testear.

Escribiendo el primer test

Vamos a añadir un test de JUnit 4 que haga uso del bean CountryService instanciado por el contexto de Spring.

  1. Necesitamos el starter spring-boot-starter-test (ya incluye JUnit 4)
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    
  2. Creamos la clase que contendrá los tests y usamos dos anotaciones:
     
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class CountryServiceTest {
    
  3. Para los tests habitualmente tendremos que utilizar parámetros de configuración específicos como por ejemplo la conexión a la base de datos. Podemos aplicar las siguientes estrategias:
    • Duplicar en el directorio /src/test/resources los ficheros de /src/main/resources y modificarlos con los parámetros para los tests. Esto incluye el application.properties.
    • Crear ficheros de propiedades completamente nuevos que sobrescriban sólo los parámetros que cambian para los tests, e indicar estos ficheros en el test con la anotación @TestPropertySource.

    Vamos a seguir la segunda estrategia para establecer la url de la base de datos en MySQL que usaremos específicamente para los tests. Por tanto se crea el fichero /src/test/resources/db-test.properties con el siguiente contenido:

    spring.datasource.url=jdbc:mysql://localhost:3306/country-test
    

    y lo definimos en el test

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @TestPropertySource(locations = "classpath:db-test.properties")
    public class CountryServiceTest {
    
  4. Puesto que estamos utilizando una base de datos en nuestro test, generalmente vamos a querer precargar un juego de datos o dataset. Esto lo hacemos creando el script sql correspondiente dentro del directorio /src/test/resources/ e indicándolo en el test con la anotación @Sql del mismo modo que se hizo en el tutorial Spring JDBC Template: simplificando el uso de SQL.
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @TestPropertySource(locations = "classpath:db-test.properties")
    @Sql("/test-mysql.sql")
    public class CountryServiceTest {
    
BEGIN;
TRUNCATE countries;

INSERT INTO `countries` (`id`, `create_by`, `created_date`, `last_modified_by`, `last_modified_date`, `name`, `population`) VALUES
    (1, 'test', '2018-11-17 18:50:06', 'test', '2018-11-17 18:50:10', 'Mexico', 130497248),
    (2, 'test', '2018-11-17 18:50:06', 'test', '2018-11-17 18:50:10', 'Spain', 49067981),
    (3, 'test', '2018-11-17 18:50:06', 'test', '2018-11-17 18:50:10', 'Colombia', 46070146);

COMMIT;

Cursos aplicaciones móviles

Ahora estamos en condiciones de inyectar en el test los beans de Spring que necesitemos, y el test finalmente queda así (antes de ejecutarlo comprobar que la conexión a la base de datos MySQL está correctamente configurada).

package com.danielme.springboot.services;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:db-test.properties")
@Sql("/test-mysql.sql")
public class CountryServiceTest {

    @Autowired
    CountryService countryService;

    @Test
    public void test() {
        assertEquals(3, countryService.findAll().size());
    }

}

El starter para testing incluye la librería AssertJ ya mencionada en el tutorial Testing con JUnit 4 y que permite escribir aserciones con una api fluida.

assertThat(countryService.findAll()).hasSize(3);

Base de datos embebida en memoria

Para pasar el test anterior es necesario tener acceso a un servidor MySQL en el que podamos realizar la prueba y que durante la realización de las mismas sea de uso exclusivo para evitar incongruencias con los datos que espera el test. Hoy en día esto no supone una gran dificultad ya que con Docker podemos instanciar un contenedor específicamente para los tests con la versión de la base de datos que utiliza la aplicación en producción. Incluso podemos integrar directamente el contenedor con JUnit con la librería TestContainers.

Tradicionalmente se ha seguido la praxis de utilizar en los tests una base de datos embebida en memoria para hacer los test de integración totalmente autónomos de sistemas externos. En nuestro ejemplo de Spring Boot se utiliza MySQL pero podemos ejecutar los tests contra una base de datos de este tipo con una de las siguientes estrategias:

  • Configurar un datasource específico para los tests. Por ejemplo, para H2 la configuración estándar es la siguiente
    spring.datasource.driver-class-name=org.h2.Driver
    spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
    spring.datasource.username=sa
    spring.datasource.password=sa
    
  • Hacer que Spring Boot lo haga automáticamente marcando el test con @AutoConfigureTestDatabase. Se reemplaza el datasource de la aplicación por uno generado para la base de datos embebida que se encuentre en el classpath (H2, HSQLDB o Derby).

En ambos casos hay que añadir la base de datos al proyecto, por ejemplo H2.

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>

Ahora creamos un nuevo script de inicialización de SQL válido para H2 teniendo en cuenta además que los cambios realizados en esta BD no serán guardados.

INSERT INTO countries (id, create_by, created_date, last_modified_by, last_modified_date, name, population) VALUES
    (1, 'test', '2018-11-17 18:50:06', 'test', '2018-11-17 18:50:10', 'Mexico', 130497248),
    (2, 'test', '2018-11-17 18:50:06', 'test', '2018-11-17 18:50:10', 'Spain', 49067981);

Para probar creamos una copia de CountryServiceTest que utilice H2.

package com.danielme.springboot.services;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:db-test.properties")
@Sql("/test-h2.sql")
@AutoConfigureTestDatabase
public class CountryServiceH2Test {

    @Autowired
    CountryService countryService;

    @Test
    public void test() {
        assertEquals(2, countryService.findAll().size());
    }

}

Revisando el log de Spring podemos comprobar que efectivamente se configura el datasource para H2.

11-17-2018 09:35:53,846 PM  INFO TestDatabaseAutoConfiguration$EmbeddedDataSourceBeanFactoryPostProcessor:106 - Replacing 'dataSource' DataSource bean with embedded version
11-17-2018 09:35:53,847 PM  INFO DefaultListableBeanFactory:821 - Overriding bean definition for bean 'dataSource' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]] with [Root bean: class [org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration$EmbeddedDataSourceFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
11-17-2018 09:35:54,341 PM  INFO PostProcessorRegistrationDelegate$BeanPostProcessorChecker:326 - Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$56f34ab] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
11-17-2018 09:35:54,429 PM  INFO EmbeddedDatabaseFactory:189 - Starting embedded database: url='jdbc:h2:mem:63084dbe-31c8-40aa-99c7-3e6e13518c95;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'

Master Pyhton, Java, Scala or Ruby

Integración con Mockito

Mockito es una librería fantástica para la creación de objetos de tipo test doubles. Puesto que ya existe el tutorial Test Doubles con Mockito, me voy a centrar sólo en la integración con Spring Boot.

Spring Boot ofrece una integración de primer nivel con Mockito gracias a las anotaciones @MockBean y @SpyBean. Ambas crean mocks y spys respectivamente que reemplazan dentro del contexto de Spring a sus beans equivalentes. Veámoslo con un ejemplo.

Creamos la clase CountryMockServiceTest análoga a CountryServiceTest en la que vamos a testear CountryService. El servicio utiliza el repositorio CountryRepository, y vamos a hacer un mock del mismo. Lo más destacable del ejemplo es el hecho de que la integración de Spring Boot con Mockito ya se encarga de que en el bean CountryService se inyecte el mock de forma totalmente automática y transparente para nosotros. Y, como cualquier otro mock, tenemos disponible la funcionalidad verify.

package com.danielme.springboot.services;

import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.LinkedList;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;

import org.springframework.test.context.junit4.SpringRunner;

import com.danielme.springboot.repositories.CountryRepository;

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:db-test.properties")
public class CountryMockServiceTest {

    @MockBean
    CountryRepository countryRepository;

    @Autowired
    CountryService countryService;

    @Test
    public void test() {
        when(countryRepository.findAll()).thenReturn(new LinkedList<>());
        assertTrue(countryService.findAll().isEmpty());
        verify(countryRepository, times(1)).findAll();
    }

}

IMPORTANTE: @SpyMock no funciona con repositorios de Spring Data JPA, consultar la issue para alternativas.

Controladores web

En Spring es posible testear directamente los controladores simulando la realización de llamadas HTTP a través de la clase MockMVC. Esto permite por ejemplo probar una api REST de forma “interna”, sin tener que desplegar la aplicación en un servidor, y poder usar mocks dentro del test.

La clase MockMVC no es exclusiva de Spring Boot ya que forma parte de Spring desde la versión 3.2, pero Spring Boot es capaz de crear y configurar automáticamente su instancia simplemente utilizando la anotación @AutoConfigureMockMvc. Esto permite inyectar en la clase de test una instancia de MockMvc que podemos utilizar directamente sin ninguna configuración adicional.

package com.danielme.springboot.controllers;

import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:db-test.properties")
@Sql("/test-mysql.sql")
@AutoConfigureMockMvc
public class CountryRestControllerTest {

    @Autowired
    private MockMvc mockMvc;

}

MockMVC ofrece una “api fluida” que permite hacer una llamada web con todos los parámetros que sean necesarios y obtener y comprobar la respuesta. No voy a analizar su uso, pero a modo de ejemplo mostraré algunos tests para el recurso definido en la clase CountryRestController.

Básicamente lo que hay que hacer es realizar la llamada a una url mediante el método perform al que pasamos la configuración de la llamada HTTP incluyendo su contenido si lo hubiera (por ejemplo el POST de un JSON). A la respuesta del perform iremos concatenando las restricciones que queremos imponer a la respuesta (andExpect) y que funcionarán a modo de assert del test.

En el ejemplo se usa la librería JsonPath, incluida en el starter de test de Spring Boot, para realizar validaciones sobre los JSON de respuesta aplicando expresiones de Hamcrest. Para realizar la serialización y deserialización de objetos Java en JSON, he inyectado ObjectMapper, el mapeador de Jackson que es configurado automáticamente por Spring.

package com.danielme.springboot.controllers;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import com.danielme.springboot.entities.Country;
import com.fasterxml.jackson.databind.ObjectMapper;

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:db-test.properties")
@Sql("/test-mysql.sql")
@AutoConfigureMockMvc
public class CountryRestControllerTest {

    private static final Logger logger = Logger.getLogger(CountryRestControllerTest.class);
    
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    ObjectMapper objectmapper;
    
    @Value("${spring.data.rest.base-path}")
    String apiRootPath;

    @Test
    public void testGetSpain() throws Exception {
        String response = mockMvc.perform(get(apiRootPath +"/country/{id}/", 2))
                .andExpect(status().is(HttpStatus.OK.value()))
                .andExpect(jsonPath("$.name", is("Spain")))
                .andReturn().getResponse().getContentAsString();

        logger.info("response: " + response);
    }
    
    @Test
    public void testAddGermany() throws Exception {
        Country country = new Country("Germany", 79778000);
        
        String response = mockMvc.perform(post(apiRootPath + "/country/")
                .content(objectmapper.writeValueAsString(country))
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().is(HttpStatus.CREATED.value()))
                .andReturn().getResponse().getContentAsString();
        
        logger.info(response);
    }
    
    @Test
    public void testAddDuplicateCountry() throws Exception {
        Country country = new Country("Spain", 1);

        String response = mockMvc.perform(post(apiRootPath + "/country/")
                .content(objectmapper.writeValueAsString(country))
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().is(HttpStatus.INTERNAL_SERVER_ERROR.value()))
                .andReturn().getResponse().getContentAsString();

        logger.info(response);
    }

}

REST Assured

Rest Assured es una librería Java para el testeo de apis REST muy utilizada. Si estamos acostumbrados a su uso podemos utilizar su API sobre MockMVC ya que existe una implementación que proporciona esta integración.

Para utilizarla, tenemos que incluir en el pom la dependencia io.rest-assured\spring-mock-mvc. La versión ya es establecida por Spring Boot.

<dependency>
  <groupId>io.rest-assured</groupId>
  <artifactId>spring-mock-mvc</artifactId>
  <scope>test</scope>
</dependency>

Los tests, en lugar de basarse en la clase io.restassured.RestAssured, deberán utilizar io.restassured.module.mockmvc.RestAssuredMockMvc para poder beneficiarnos de la integración con MockMVC.

A continuación se muestra una implementación alternativa a testGetSpain basada en REST Assured. Obsérvese que hay que proporcionar a RestAssuredMockMvc la instancia de MockMVC que debe utilizar, generalmente esto lo haremos en el método @Before de la clase JUnit si tenemos que hacerlo para todos los tests que contenga la clase.

    @Test
    public void testRestAssured() {
        RestAssuredMockMvc.mockMvc(mockMvc);
        
        when().get(apiRootPath + "/country/{id}/", 2)
        .then().statusCode(HttpStatus.OK.value())
                .body("name", equalTo("Spain"));
    }

JUnit 5

Spring Boot test proporciona JUnit 4 pero podemos utilizar JUnit 5 para escribir los tests (o incluso ambas versiones a la vez).

  • JUnit 5: añadimos las siguientes dependencias
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <scope>test</scope>
    </dependency>
    

    excluimos JUnit 4 para evitar confundirnos con las clases

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
    	    <groupId>junit</groupId>
    	    <artifactId>junit</artifactId>
    	</exclusion>
        </exclusions>
    </dependency>
    

    Nos aseguramos de utilizar como mínimo la versión 2.22.0 del plugin surefire de Maven cuya responsabilidad es ejecutar los tests. La versión de este plugin ya es configurada por Spring Boot pero en el proyecto de ejemplo (Spring Boot 2.0.6) se utiliza la 2.21.0.

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.0</version>
        <configuration>
            <useSystemClassLoader>false</useSystemClassLoader>
        </configuration>
    </plugin>
    
  • JUnit 4 y JUnit 5. Además de los cambios anteriores, excepto la exclusión de JUnit 4, añadimos la siguiente librería que proporciona soporte para la ejecución de tests implementados con JUnit 3 y JUnit 4 utilizando el nuevo engine de JUnit 5.
    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <scope>test</scope>
    </dependency>
    

En ambos casos, si no utilizamos una versión muy reciente de Eclipse es posible que los tests no puedan ejecutarse y se produzca el siguiente error

java.lang.NoClassDefFoundError: org/junit/platform/launcher/core/LauncherFactory
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.(JUnit5TestLoader.java:31)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.lang.Class.newInstance(Class.java:442)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.createRawTestLoader(RemoteTestRunner.java:367)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.createLoader(RemoteTestRunner.java:362)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.defaultInit(RemoteTestRunner.java:306)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.init(RemoteTestRunner.java:221)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:205)
Caused by: java.lang.ClassNotFoundException: org.junit.platform.launcher.core.LauncherFactory
	at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 11 more

Se soluciona añadiendo la siguiente librería al pom.

<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-launcher</artifactId>
    <version>1.1.0</version>
    <scope>test</scope>
</dependency>

A modo de ejemplo, la siguiente clase implementa con JUnit 5 el test CountryServiceTest. Aquí ya no usamos un runner para integrar el test con Spring sino el nuevo mecanismo de extensiones de JUnit 5 con la extensión SpringExtension.

package com.danielme.springboot.services;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:db-test.properties")
@Sql("/test-mysql.sql")
public class CountryServiceJUnit5Test {

    @Autowired
    CountryService countryService;

    @Test
    public void test() {
        assertEquals(3, countryService.findAll().size());
        // assertj
        assertThat(countryService.findAll()).hasSize(3);
    }

}

En JUnit 5 podemos utilizar las anotaciones de Spring @EnabledIf y @DisabledIf que habilitan y deshabilitan respectivamente la ejecución de los tests evaluando una expresión SpEL. Estas anotaciones pueden aplicarse tanto a un método de test como a una clase completa.

Por ejemplo, el siguiente test se ejecuta en función del valor de la propiedad spring.datasource.username definida en el application.properties; en este caso concreto es necesario activar el flag loadContext porque la expresión requiere utilizar el contexto de Spring.

@EnabledIf(expression = "#{'${spring.datasource.username}' != 'demo' }", loadContext = true)
@Test
public void testIf1() {
    fail("fail");
}

El siguiente test está copiado directamente de la documentación y sólo se ejecuta en plataformas Linux.

@EnabledIf("#{systemProperties['os.name'].toLowerCase().contains('linux')}")
@Test
public void testIf2() {
    fail("fail");
}

Código de ejemplo

El proyecto completo se encuentra disponible en GitHub. Para más información sobre cómo utilizar GitHub, consultar este artículo.

También se encuentran en GitHub los ejemplos oficiales de Spring Boot.

Otros tutoriales relacionados

Introducción a Spring Boot: Aplicación Web con servicios REST y Spring Data JPA
Testing Spring con JUnit 4
Testing con JUnit 4
Persistencia en BD con Spring Data JPA
Spring JDBC Template: simplificando el uso de SQL
Persistencia en BD con Spring: Integrando JPA, c3p0, Hibernate y EHCache

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.