Unit test with the database

8

I have an application that uses JPA 2 with Hibernate behind and for unit tests, I use HSQLDB in memory with JUnit 4.11. The HSQLDB is configured in a persistence.xml file in a META-INF folder.

My question is: How do I upload the clean database at the beginning of each test without having to manually call a bunch of "DELETE FROM BLABLA" or something similar?

Currently I have problems within the methods @Before , a call something like this:

EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);

The% s of the% s produced are placed in a EntityManager variable, to ensure that each thread does not manipulate the% s of% s of other threads.

In methods ThreadLocal I call a EntityManager .

However, the test is not reliable. Sometimes saved objects disappear for no apparent reason. And often the Hibernate cache fools me by showing objects that are not persisted, but they seem to be, and so I end up abusing the use of @After as a precaution in places where this should not be necessary.

Does anyone have a better suggestion of some strategy for developing tests using HSQLDB in memory with JUnit?

    
asked by anonymous 13.12.2013 / 01:06

3 answers

5

You have EntityManager per thread, but all share the same database. If you run the tests concurrently, what one test does, may affect the other tests.

It is necessary to create the bank in memory with each test.

I'll quote a tutorial . Where it creates a hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                                         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory name="">
  <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
  <property name="hibernate.connection.url">jdbc:hsqldb:mem:testdb;shutdown=false</property>
  <property name="hibernate.connection.username">sa</property><!-- default username -->
  <property name="hibernate.connection.password"/><!-- default password -->
  <property name="hibernate.connection.pool_size">10</property>
  <property name="hibernate.connection.autocommit">true</property>
  <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
  <property name="hibernate.hbm2ddl.auto">create-drop</property><!-- creates the tables from the entites automatically -->
  <property name="show_sql">true</property>
  <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
  <mapping class="blog.hibernate.employee.Employee"/>
 </session-factory>
</hibernate-configuration>

And put in% test%:

    @BeforeClass
    public void init() {
        config = new AnnotationConfiguration();
        config.configure(new File("hibernate.cfg.xml"));
            factory = config.buildSessionFactory();
            hibernateSession = factory.openSession();
        }

It's a little old tutorial, but it should be pretty close to what you need to do in this version of Hibernate.

    
13.12.2013 / 01:34
2

There is a Hibernate property that is named hibernate.hbm2ddl.auto . When it is in create-drop , it will erase everything and recreate from scratch, ideal situation for your tests. What I usually do is have a base class that is in charge of re-creating the database with each test. Note that this happens with each test method, making running your tests slow, but it's a price I think it's fair to pay. A good reference source is Hibernate's own test suite. They use a different output, which is to re-create the database for each class. To do this, they use some JUnit extensions, which may be too much for the normal case.

Here are some examples I use for personal projects, which may be an inspiration:

META-INF / persistence.xml

, with nothing more, except the property that erases and rebuilds the database.

TestWithEntityManager

, base class for tests that require database.

CategoryServiceTest

, an example of a class that uses the TestWithEntityManager.

    
13.12.2013 / 09:56
1

As already mentioned in other answers, Hibernate is able to create the database structure by setting the hibernate.hbm2ddl.auto property.

However, the use of this feature is impracticable in somewhat more complex scenarios where, for example, there is a DBA in the process. There are many other issues in this regard, as we often need fine-tuning in the database: index creation, DBMS-specific structures, data loads.

Solutions to this have come in this year's JPA 2.1 specification, which allow SQL scripts to run before or after the metadata construct of the database, or only the scripts to run. See some articles about the subject. So it would be possible to define a script to create the necessary database structure at the beginning of each test.

Another approach to creating a "frankenstein" that blends unit testing and integration (I do not want to get into the discussion of what is) is to use a testing framework that allows for some further adjustments, such as TestNG . This has an API very similar to JUnit, but with some extra features:

  • Specify dependency between tests or test group (affects order of execution)
  • Specify tests that may or may not run in parallel
  • Tests parameterized with a Data Provider

(For comparisons between JUnit and TestNG see these links .)

Finally, I made a brief presentation about TestNG because it allows you to create something between a unit test and an integration test through test groupings and dependency between them.

For example, one could create a @Test processarContratos() test that depended on the test @Test incluirCliente() (which includes a client) and the @TestincluirContrato(Contrato c) test (which is linked to a DataProvider and includes several contracts). Methods annotated with @BeforeSuite and @AfterSuite can be used to initialize and terminate the resources required for the methods of a Test Suit .

    
13.12.2013 / 12:01