unitarias unit test pruebas net mvc unit-testing playframework playframework-2.0 database-testing

unit testing - test - ¿Cómo crear pruebas unitarias contra bases de datos que no están en la memoria, como MySQL en el marco de Play, y restablecer el estado conocido?



pruebas unitarias.net core (5)

¿Alguien utilizó este enfoque (haciendo que las evoluciones sean compatibles con MySQL y H2)?

He encontrado una respuesta para las características específicas de MySQL: ¿Cómo puedo realizar una prueba unitaria para la base de datos MySQL con Play 2.x?

Quiero crear pruebas unitarias que cubran el código que usa la base de datos relacional en Play framework 2.1.0. Hay muchas posibilidades para esto y todos causan problemas:

Pruebas en base de datos H2 en memoria

La documentación de Play Framework propone ejecutar pruebas unitarias en la base de datos en memoria H2, incluso si la base de datos principal utilizada para el desarrollo y la producción utiliza otro software (es decir, MySQL):

app = Helpers.fakeApplication(Helpers.inMemoryDatabase());

Mi aplicación no usa funciones RDBMS complicadas, como los procedimientos almacenados y la mayoría de los casos de acceso a bases de datos son llamadas de ebean, por lo que debe ser compatible con MySQL y H2.

Sin embargo, las declaraciones de creación de tablas en evoluciones usan características específicas de MySQL, como especificar ENGINE = InnoDB , DEFAULT CHARACTER SET = utf8 , etc. Me temo que si DEFAULT CHARACTER SET = utf8 estas partes propietarias de CREATE TABLE , MySQL usará una configuración predeterminada que puedo No se puede controlar y eso depende de la versión, por lo que para probar y desarrollar la configuración principal de MySQL de la aplicación se debe modificar.

¿Alguien utilizó este enfoque (haciendo que las evoluciones sean compatibles con MySQL y H2)?

Otras ideas de cómo se puede manejar:

  • Evoluciones separadas para MySQL y H2 (no es una buena idea)
  • Alguna forma de hacer que H2 ignore las cosas de MySQL adicionales en la create table (el modo de compatibilidad de MySQL no funciona, aún se queja incluso del default character set ). No se como

Prueba en el mismo controlador de base de datos que la base de datos principal

La única ventaja de la base de datos en memoria H2 es que es rápida, y las pruebas en el mismo controlador de base de datos que en la base de datos dev / production pueden ser mejores, ya que están más cerca del entorno real.

¿Cómo se puede hacer bien en Play framework?

Intentó:

Map<String, String> settings = new HashMap<String, String>(); settings.put("db.default.url", "jdbc:mysql://localhost/sometestdatabase"); settings.put("db.default.jndiName", "DefaultDS"); app = Helpers.fakeApplication(settings);

Parece que las evoluciones funcionan aquí, pero ¿cuál es la mejor forma de limpiar la base de datos antes de cada prueba? ¿Creando código personalizado que trunca cada tabla? Si se eliminarán las tablas, ¿se ejecutarán nuevamente las evoluciones antes de la próxima prueba o se aplicarán una vez por cada comando de play test ? ¿O una vez por Helpers.fakeApplication() invocación de Helpers.fakeApplication() ?

¿Cuáles son las mejores prácticas aquí? Oído sobre dbunit , ¿es posible integrarlo sin mucho dolor y peculiaridades?


Cuando escribí mis pruebas para mi base de datos de Postgres, simplemente creé un HashMap para conectarme a la base de datos, y luego escribí consultas de prueba para asegurarme de que existiera la cantidad correcta de registros, y así sucesivamente ... Aquí está mi código.

@Test public void testDataBase() { final HashMap<String,String> postgres = new HashMap<String, String>(); postgres.put("db.default.driver","org.postgresql.Driver"); postgres.put("db.default.url","jdbc:postgresql://localhost/myDataBase"); postgres.put("db.default.user", "postgres"); postgres.put("db.default.password", "password"); running(fakeApplication(postgres), new Runnable() { @Override public void run() { //Insert Assertions Here } }); }


Primero, le recomendaría que use el mismo RDBMS para pruebas y producción, ya que podría evitar algunos errores difíciles de encontrar.

Con respecto a la necesidad de limpiar su base de datos entre cada prueba, puede usar Ebean DdlGenerator para generar scripts para crear una base de datos limpia y la anotación @Before de JUnit para ejecutar automáticamente estos scripts antes de cada prueba.

Usando el DdlGenerator se puede hacer así:

EbeanServer server = Ebean.getServer(serverName); ServerConfig config = new ServerConfig(); DdlGenerator ddl = new DdlGenerator((SpiEbeanServer) server, new MySqlPlatform(), config);

Este código se puede colocar en una clase base que podría hacer heredar sus pruebas (o dentro de un Runner personalizado que puede usar con la anotación @RunWith ).

También le permitirá automatizar fácilmente la creación de aplicaciones FakeApplication , evitando algunos códigos repetitivos.

Algunos enlaces que pueden ser útiles:


También puede usar DB simulado, si el objetivo es validar sus asignaciones y funciones de Slick | JPA | Anorm basadas en.

Cuando está en condiciones, tiene la ventaja de ser más compatible con las pruebas unitarias que un DB de prueba y más fácil de administrar (no configurar / borrar tareas, no sincronizar las pruebas para evitar el acceso a las mismas tablas de prueba).

Puede consultar Acolyte (acolyte.eu.org) que se usa en las especificaciones de Anorm (p. Ej., https://github.com/playframework/playframework/blob/master/framework/src/anorm/src/test/scala/anorm/SqlResultSpec.scala ).


Utilicé el mismo motor de base de datos que la base de datos principal y dbunit para limpiar antes de cada prueba.

public class SomeTest { // ... @Before public void startApp() throws Exception { // Set up connection to test database, different from main database. Config better should be used instead of hard-coding. Map<String, String> settings = new HashMap<String, String>(); settings.put("db.default.url", "jdbc:mysql://localhost/somedatabase?characterEncoding=UTF-8&useOldAliasMetadataBehavior=true"); settings.put("db.default.user", "root"); settings.put("db.default.password", "root"); settings.put("db.default.jndiName", "DefaultDS"); // make connection available to dbunit through JNDI app = Helpers.fakeApplication(settings); Helpers.start(app); databaseTester = new JndiDatabaseTester("DefaultDS"); IDataSet initialDataSet = new FlatXmlDataSetBuilder().build(play.Play.application() .resourceAsStream("/resources/dataset.xml")); databaseTester.setDataSet(initialDataSet); databaseTester.onSetup(); } @After public void stopApp() throws Exception { databaseTester.onTearDown(); Helpers.stop(app); } }

Mi dataset.xml solo contiene nombres de tablas para decirle a dbunit que vacíe estas tablas antes de cada prueba. También puede contener accesorios.

<?xml version="1.0" encoding="UTF-8"?> <dataset> <name_of_my_first_table /> <name_of_my_second_table /> </dataset>

Las evoluciones se ejecutan automáticamente en la base de datos de prueba cuando se utiliza este enfoque, por lo que si elimina todas las tablas de la base de datos de prueba, se volverán a crear.

Es excesivo utilizar dbunit si solo necesita limpiar las tablas, puede limpiarlas emitiendo la consulta directamente o utilizando ebean DdlGenerator . Pero también uso dbunit para comparar datos.

No utilizo Helpers.running , ya que las implementaciones Runnable y Runnable no pueden Runnable excepciones, lo que es muy inconveniente para las pruebas. Pero si miras el código para running() , solo llama a Helpers.start() y Helpers.stop() así que llamo a estos métodos directamente en @Before y @Before .

Decidió no usar H2 para ejecutar pruebas: sí, se ejecuta más rápido, pero hay demasiada diferencia entre MySQL y este.