I'm having a Java EE application that runs on JBoss 7. In order to do TDD, I'm setting up embedded tests that use Arquillian with embedded Weld and a H2 embedded database.
This works fine, but the initial startup of Hibernate takes a considerable amount of time (5-10 seconds) and I haven't included all JPA entities yet. I have tried to use a persisted Oracle DB instead to avoid table creation, but it doesn't make much of a difference.
The main problem seems to be that Hibernate goes through all the entities and validates and prepares all the CRUD methods, named queries and so on.
Is there any way to tell Hibernate to do this lazily when needed (or not at all)? Most of the time, there will only be a subset of entities and queries involved in a test case, so I'd happily trade in execution time for start-up time while implementing.
Any ideas?
I know I could just use a subset of the entities, but it's sometimes difficult as they often have relations to other entities not needed in a test context. Or is there an easy way to 'deactivate' such relations to generate subsets of the database?
Clarification
It seams like it's not clear what my problem is, so I'll try to clarify:
I have set up a testing environment with Arquillian (embedded Weld) that sets up an embedded database (H2) to do JPA enabled testing
I would like to use this approach to do Test Driven Development (TDD), which means I will have the following workflow on my local developing machine:
Create test case
Run test case
If test case fails, implement necessary changes and go back to 2.
Normally, one will perform steps 2 and 3 a couple of times before finishing a feature which means that I will often run a single test from my IDE that has to set up the entire testing JVM with Arquillian, Weld, embedded DB and whatever to run just A SINGLE TEST.
So much for the scenario. Now I've noticed that running that single test takes around 10 seconds, which is not the end of the world, but rather long to do TDD. And when I further investigated, I've noticed that most of this time goes to Hibernate setting up its internal structures (it's not Weld, Arquillian, Schema creation or whatever, but Hibernate getting ready to provide an EntityManager).
So my question is: Is there a way to speed up hibernate initialization so I can drop these 10 seconds to maybe 1-2 seconds? I wouldn't care if it's sort of a hack (like keeping the testing JVM with hibernate alive during multiple manual test runs or deactivating some validations or optimizations of Hibernate). My only issue is the start up time for a single test. Consecutive tests run fine and fast, so I don't have a problem with full regression testing or with testing on my build server.
Hope that makes my case a bit clearer...
Let me guess, you are using junit library?
Database schema creation usually isn't the most time-consuming operation (although it depends on amount of entities).
Personally, if I were you, I would run all your JUnit tests with TestNG (yes, TestNG can run all JUnit tests out of the box) and would take a look at <your-module>/test-output/index.html (particularly its sections Chronological view and Times). Then you would know what operations are the most time-consuming. And with such information, you can go further.
Furthermore, a couple of items of advice:
Arquillian tests with a remote (or managed) containers are usually faster, because you start server only once.
H2 embedded database isn't a bad choice, really. Typically you don't have to abandon it (typically, because sometimes your application may use some of the target database features, that are not present in the H2).
There is Arquillian Suite Extension that lets you do deployment only once and reuse it across the test classes. In case of many tests, this extension can speed up tests execution significantly.
You can test your entities outside any container (so called standalone JPA with transaction-type="RESOURCE_LOCAL"). It is the fastest way, but suits well only for testing entities annotations, relations, queries and so on.
Edit
There is number of ways to do your task much better. Just a couple of points:
You don't have to re-create database every time. Even embedded databases (H2, HSQLDB, Derby) have server mode in which they last longer than JVM.
If Hibernate initialization bothers you, then do it once across the all tests (I mean keeping EntityManagerFactory between unit tests).
If you want to avoid a database creation, just use H2 in server mode and set hibernate to not do any changes (<property name="hibernate.hbm2ddl.auto" value="none" />)
Related
I develop an application in Java with Spring and Hibernate. And now I am looking for a solution for fast reloading data between tests. The tests require a lot of data, which are generated and persisted through services. As a db I use hsqldb in memory. Data generating process takes about 30 seconds, so it is too long to simply run it before each test.
So I was wondering if it is good idea and if it is possible with hsqldb to run data loader once at the begining of test case or suite, then create a dump and restore it before each test? I can't find how to create dump in hsqldb, especially if it is in memory db.
I appreaciate all yours help.
EDIT: I have to use database. Let's consider that they re integration tests.
You can use dbUnit to load and clean the database before and after each test but I don't think that will improve your performance.
Instead, I would ask why you need so much data for a unit test? 30 seconds isn't too bad for an integration test that actually hits a database, but I think you should strive to have unit tests that don't hit the database at all and instead use mock objects to simulate interacting with your services. Then you can have a few integration tests that actually use a database but those tests won't have to cover all scenarios since your faster unit tests should do that already.
You can use an HSQLDB file: database with the default MEMORY tables.
After generating the dataset, add the property files_readonly=true to the database.properties file. You then run the tests with this database. This ensures your tests run and modify the data the same way as a mem: database, but the changes made by the tests are not persisted when the test process ends. The original data is loaded in a few seconds in the fastest possible way.
try using this annotation in your test class
#TransactionConfiguration(transactionManager="nameOfYourTransactionManager", defaultRollback=true)
I found it here
I am wondering what people have found their best practice to be for testing Hibernate mappings and queries ?
This cannot be done with Unit Testing, so my experience has been to write Integration Tests that solely tests the DAO layer downwards. This way I can fully test each Insert / Update / Delete / ReadQueries without testing the full end-to-end solution.
Whenever the Integration test suite is run it will:-
Drop and re-create the database.
Run an import SQL script that contains a subset of data.
Run each test in a Transactional context that rolls back the transaction. Therefore it can be run multiple times as an independent test, or and as part of a suite, and the same result is returned as the database is always in a known state.
I never test against a different "in memory" database, as there is always an equivalent development database to test against.
I have never had the need to use DBUnit.
Never use DbUnit for this. It's way too much overhead for this level of testing.
Especially if you're using Spring in your app, check out the Spring Test Framework to help manage your data-access tests, particularly the transaction management features.
An "equivalent development database" is fine, but an in-memory H2 database will blow away anything else for speed. That's important because, while the unit/integration status of these tests may be contested, they're tests you want to run a lot, so they need to be as fast as possible.
So my DAO tests look like this:
Spring manages the SessionFactory and TransactionManager.
Spring handles all transactions for test methods.
Hibernate creates the current schema in an in-memory H2 database.
Test all the save, load, delete, and find methods, doing field-for-field comparison on before and after objects. (E.g. create object foo1, save it, load it as foo2, verify foo1 and foo2 contain identical values.)
Very lightweight and useful for quick feedback.
If you don't depend on proprietary rdbms features (triggers, stored procedures etc) then you can easily and fully test your DAOs using JUnit and an in memory database like HSQLDB. You'll need some rudimentary hibernate.cfg.xml emulation via a class (to initialize hibernate with HSQLDB, load the hbm.xml files you want) and then pass the provided datasource to your daos.
Works well and provides real value to the development lifecycle.
The way I do it is pretty similar with your own, with the exception of actually using in-memory data-bases, like HSQLDB. It's faster and more portable than having a real database configured (one that runs in a standalone server). It's true that for certain more advanced features HSQLDB won't work as it simply does not support them, but I've noticed that I hardly run into those when just integration testing my data access layer. However if this is the case, I like to use the "jar" version of mysql, which allows me to start a fully functional MYSql server from java, and shut it down when I'm done. This is not very practical as the jar file is quite big :
http://dev.mysql.com/doc/refman/5.0/en/connector-mxj-configuration-java-object.html
but it's still useful in some instances.
At work we are trying to simplify an application that was coded with an overkill use of Spring Remoting. This is how it works today:
(Controllers) Spring MVC -> Spring Remoting -> Hibernate
Everything is deployed in a single machine, Spring Remoting is not needed (never will be needed) and adds complexity to code maintenance. We want it out.
How to ensure everything works after our changes? Today we have 0% code coverage! We thought on creating integration tests to our controllers so when we remove Spring Remoting they should behave exactly the same. We thought on using a mix of Spring Test framework in conjunction with DBUnit to bring up Oracle up to a known state every test cycle.
Has anyone tried a similar solution? What are the drawbacks? Would you suggest any better alternative?
It always depends on the ratio effort / benefit that you are willing to take. You can get an almost 100% code coverage if you are really diligent and thorough. But that might be overkill too, especially when it comes to maintaining those tests. But your idea is good. I've done this a couple of times before with medium applications. This is what you should do:
Be sure that you have a well known test data set in the database at the beginning of every test in the test suite (you mentioned that yourself)
Since you're using Hibernate, you might also try using HSQLDB as a substitute for Oracle. That way, your tests will run a lot faster.
Create lots of independent little test cases covering most of your most valued functionality. You can always allow yourself to have some minor bugs in some remote and unimportant corners of the application.
Make sure those test cases all run before the refactoring.
Make sure you have a reference system that will not be touched by the refactoring, in order to be able to add new test cases, in case you think of something only later
Start refactoring, and while refactoring run all relevant tests that could be broken by the current refactoring step. Run the complete test suite once a night using tools such as jenkins.
That should work. If your application is a web application, then I can only recommend selenium. It has a nice jenkins integration and you can create hundreds of test cases by just clicking through your application in the browser (those clicks are recorded and a Java/Groovy/other language test script is generated).
In our Spring MVC / Hibernate (using v3.4) web app we use an Oracle database for integration testing.
To ensure that our database is in a known state each time the test suites are run, we set the following property in our test suite's persistence.xml:
<property name="hibernate.hbm2ddl.auto" value="create"/>
This ensures that the db schema is created each time our tests are run based on the Hibernate annotations in our classes. To populate our database with a know data set, we added a file named import.sql to our classpath with the appropriate SQL inserts. If you have the above property set, Hibernate will run the statements in import.sql on your database after creating the schema.
I have a small web application configured with Guice, Jersey and EclipseLink, and run this application on jetty (8.0.0.M1) during development. There are about 10 (small) JPA managed classes (entities and embeddables), and about 20 classes total.
The initial startup takes 15 seconds + 5 seconds for the first requests. It seems like JPA is working on the first request, since I have the table generation strategy "create" enabled and see some JPA output from Maven on the first request.
A reload takes about 10 seconds and the first request after reloading takes about 3 to 4 seconds.
You may think, that the startup time is not so bad, but I'm wondering if I could accelerate the startup to work more fluently like with Django. Any idea for startup tuning?
I'm afraid that if you are not prepared to remove the table creation strategy, you will have to tolerate such loading times. In essence, everytime your startup your application, it will drop/create/verify the tables and issue the correct DDL statements to make it match the entities in your package.
Assuming that you're done defining your entities and you are working on some business-logic code, you can create the database once, and just re-use your initial setup.
I imagine you are using Jetty for rapid application development (RAD) and you want to see and test out any changes as quickly as possible. If there is no actual "persistent" requirement on your RAD environment's database, you could try moving to an im-memory DB engine. DB engine's like HSQL allow you to spin up new tables (and other structures) very rapidly compared to actual production quality DB engines. This would require that you use an ORM because HSQL's SQL is very different then most other databases but it sounds like you are already using JPA so this shouldn't be difficult.
The only alternative I see is using a database which has it's schema already created appropriately and not dropping it every time.
My integration tests would run much faster if I used in-memory-database instead of PostgreSQL. I use JPA (Hibernate) and I need an in-memory-database that would be easy to switch to using JPA, easy to setup, and reliable. It needs to support JPA and Hibernate (or vice verse if you will) rather extensively since I have no desire to adopt my data access code for tests.
What database is the best choice given requirements above?
For integration testing, I now use H2 (from the original author of HSQLDB) that I prefer over HSQLDB. It is faster (and I want my tests to be as fast as possible), it has some nice features like the compatibility mode, the dev team is very responsive (while HSQLDB remained dormant for years until very recently).
I've been using HSQLDB in-memory for integration testing JPA/Hibernate persistence in Java. Starts pretty quickly, doesn't require any special setup.
The only issue I've seen so far with using HSQLDB with Hibernate was to do with batch size needing to be set to 0, but that might just have been related to an old version. I'll have a dig and see if I can find details of that problem.
Derby supports an in-memory mode these days, it is no longer marked experimental.
I use Derby. For one thing it is about 3 less lines of code per unit test since there is no need for a shutdown after the test. However, you need to use a JPA implementation that can drop and create tables such as EclipseLink.
Derby can also initialize a new in-memory database from a file so you can have a reference database and revert to it at anytime.
For unit testing though, I prefer to create my objects in my unit test's #Before logic I find it easier especially with JPA as it allows me the flexibility to do refactorings and not have to worry about the underlying database structure, other tools such as DBunit rely on practically a static structure and refactoring implies changing of the DBunit XMLs manually rather than relying on Eclipse's refactoring capabilities.