2010-08-05 18 views
11

Tengo que probar algunos servicios Thrift usando Junit. Cuando ejecuto mis pruebas como un cliente Thrift, los servicios modifican la base de datos del servidor. No puedo encontrar una buena solución que pueda limpiar la base de datos después de ejecutar cada prueba. La limpieza es importante, especialmente porque los ID deben ser únicos y actualmente se leen como un archivo XML. Ahora, tengo que cambiar manualmente los ID después de ejecutar las pruebas, de modo que el siguiente conjunto de pruebas pueda ejecutarse sin tirar la violación de la clave principal en la base de datos. Si puedo limpiar la base de datos después de cada prueba, entonces el problema está completamente resuelto, de lo contrario tendré que pensar en otras soluciones, como generar ID aleatorios y usarlos donde se requieran ID.Limpieza de la base de datos después de las pruebas Junit

Editar: Me gustaría hacer hincapié en que estoy probando un servicio, que está escribiendo en la base de datos, no tengo acceso directo a la base de datos. Pero dado que el servicio es nuestro, puedo modificar el servicio para proporcionar cualquier método de limpieza si es necesario.

Respuesta

6

A menos que esté probando acciones específicas de la base de datos (verificando que puede consultar o actualizar la base de datos, por ejemplo), sus JUnits no deberían estar escribiendo en una base de datos real. En su lugar, debe burlarse de las clases de la base de datos. De esta forma, no tiene que conectarse y modificar la base de datos y, por lo tanto, no se necesita ninguna limpieza.

Puede burlarse de sus clases de diferentes maneras. Puede usar una biblioteca como JMock que hará todo el trabajo de ejecución y validación para usted. Mi forma favorita de hacer esto es con Dependency Injection.De esta forma puedo crear clases simuladas que implementan mis interfaces de repositorio (¿está utilizando interfaces para su capa de acceso a datos, ¿verdad? ;-)) e implemento solo los métodos necesarios con acciones/valores de retorno conocidos.

//Example repository interface. 
public interface StudentRepository 
{ 
    public List<Student> getAllStudents(); 
} 

//Example mock database class. 
public class MockStudentRepository implements StudentRepository 
{ 
    //This method creates fake but known data. 
    public List<Student> getAllStudents() 
    { 
     List<Student> studentList = new ArrayList<Student>(); 
     studentList.add(new Student(...)); 
     studentList.add(new Student(...)); 
     studentList.add(new Student(...)); 

     return studentList; 
    } 
} 

//Example method to test. 
public int computeAverageAge(StudentRepository aRepository) 
{ 
    List<Student> students = aRepository.GetAllStudents(); 
    int totalAge = 0; 
    for(Student student : students) 
    { 
     totalAge += student.getAge(); 
    } 

    return totalAge/students.size(); 
} 

//Example test method. 
public void testComputeAverageAge() 
{ 
    int expectedAverage = 25; //What the expected answer of your result set is 
    int actualAverage = computeAverageAge(new MockStudentRepository()); 

    AssertEquals(expectedAverage, actualAverage); 
} 
+21

"' A menos que esté probando acciones específicas de la base de datos (verificando que puede consultar o actualizar la base de datos, por ejemplo) sus JUnits no deberían estar escribiendo en una base de datos real. "No hay un acuerdo universal sobre esto. En un campo, tenemos personas que creen que la base de datos debe ser burlada y, por otro lado, tenemos aquellas que creen que todas las pruebas de bases de datos deben realizarse contra una base de datos real, idealmente una que coincida con la base de datos de producción. – Behrang

+0

Lo siento, soy un poco nuevo en todo esto, estaba codificando en flex por un tiempo. ¿Podrían explicar lo que debo hacer? No estoy seguro de lo que quiere decir con clases simuladas y no modificando la base de datos. Normalmente, las pruebas que realizo crean nuevos clientes y utilizan ese cliente para crear pedidos y otras cosas. ¿A dónde iría toda esta información si no fuera a una base de datos? – Ashish

+0

Cuando necesite recuperar datos, cree una clase e implemente el método, necesita devolver los datos que necesita. Si necesita guardar datos, cree una clase e implemente el método de guardar (como se llame). Este método solo puede almacenar los datos en variables de instancia. Si necesita guardar y recuperar, entonces esos métodos solo necesitan leer y escribir desde las mismas variables de instancia. – brainimus

2

Suponiendo que tiene acceso a la base de datos: Otra opción es crear una copia de seguridad de la base de datos justo antes de las pruebas y restaurar desde esa copia de seguridad después de las pruebas. Esto puede ser automatizado

+0

Sí, tengo acceso a la base de datos y eso es lo que también planeo hacer después de hablar con un par de colegas. gracias John. – Ashish

1

Si está utilizando Spring + Junit 4.x, entonces no necesita insertar nada en la base de datos. Mire AbstractTransactionalJUnit4SpringContextTests clase.

También consulte la documentación de Spring para el soporte de JUnit.

4

El marco de pruebas de unidades de Spring tiene amplias capacidades para tratar con JDBC. El enfoque general es que las pruebas unitarias se ejecutan en una transacción, y (fuera de su prueba) la transacción se retrotrae una vez que se completa la prueba.

Esto tiene la ventaja de poder utilizar su base de datos y su esquema, pero sin realizar ningún cambio directo en los datos. ¡Por supuesto, si realizas un commit dentro de tu prueba, entonces todas las apuestas están apagadas!

Para obtener más información, consulte Spring's documentation en pruebas de integración con JDBC.

1

Es un poco draconiano, pero generalmente intento eliminar la base de datos (o solo las tablas que me interesan) antes de cada ejecución del método de prueba. Esto no tiende a funcionar ya que paso a más pruebas de tipo de integración, por supuesto.

En los casos en que no tengo control sobre la base de datos, supongo que quiero verificar el número correcto de filas creadas después de una llamada determinada, la prueba contará el número de filas antes y después de la llamada probada, y seguro que la diferencia es correcta En otras palabras, tenga en cuenta los datos existentes, luego vea cómo el código probado cambió las cosas, sin asumir nada sobre los datos existentes. Puede ser un poco difícil de configurar, pero permítanme probar en un sistema más "en vivo".

En su caso, ¿los identificadores específicos son importantes? ¿Podrías generar las identificaciones sobre la marcha, quizás al azar, verificar que todavía no están en uso, y luego proceder?

4

Al escribir las pruebas JUnit, puede anular dos métodos específicos: setup() y tearDown(). En setUp(), puede configurar todo lo que sea necesario para probar su código para que no tenga que configurar nada en cada caso de prueba específico. tearDown() se ejecuta después de ejecutar todos los casos de prueba.

Si es posible, puede configurarlo para que pueda abrir su base de datos en el método setUp() y luego tener todo claro de las pruebas y cerrarlo en el método tearDown(). Así es como hemos hecho todas las pruebas cuando tenemos una base de datos.

Aquí está un ejemplo:

@Override 
protected void setUp() throws Exception { 
    super.setUp(); 
    db = new WolfToursDbAdapter(mContext); 
    db.open(); 

    //Set up other required state and data 
} 

@Override 
protected void tearDown() throws Exception { 
    super.tearDown(); 
    db.dropTables(); 
    db.close(); 
    db = null; 
} 

//Methods to run all the tests 
1

Estoy de acuerdo con Brainimus si está tratando de poner a prueba frente a los datos que se han retirado de una base de datos. Si está buscando probar las modificaciones realizadas en la base de datos, otra solución sería simular la base de datos. Existen varias implementaciones de bases de datos en memoria que puede usar para crear una base de datos temporal (por ejemplo, durante el JUnit setUp()) y luego eliminar toda la base de datos de la memoria (durante tearDown()). Siempre que no esté utilizando un SQL específico del proveedor, esta es una buena forma de probar la modificación de una base de datos sin tocar la de producción real.

Algunas buenas bases de datos Java que se ofrecen en el soporte de memoria son Apache Derby, Java DB (pero en realidad es el sabor de Apache Derby de Oracle de nuevo), HyperSQL (más conocido como HSQLDB) y H2 Database Engine. Personalmente, utilicé HSQLDB para crear bases de datos simuladas en memoria para probar y funcionó de maravilla, pero estoy seguro de que los demás ofrecerían resultados similares.

10

Si está utilizando Spring, todo lo que necesita es la anotación @DirtiesContext en su clase de prueba.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("/test-context.xml") 
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) 
public class MyServiceTest { 
    .... 
} 
+2

DirtiesContext se trata de la recreación del contexto Spring - es una operación lenta, por lo que no es una buena manera –

Cuestiones relacionadas