How should I unit test methods which their intent is querying the database and return some data? For other situations I can just mock the objects but in this case which I want to test whether they return the correct data, how should I check it isolated from db? Should I use some kind of special db? But then how should I configure that new db to work like the other one with all those columns, etc?
Thanks.
Update: Thanks to everyone, their responses leaded me to the correct path. I finally used debry. I just added a new persistence.xml for that. No other significant changes and it seems to be working now.
One approach I've used with great success is to use:
Maven to build your project
Liquibase (or Flyway) to manage your database schema, and versioning it
H2 as an in-memory database that is started along with your tests.
There's a fair bit to learn there if you haven't used any of the above, but in my experience it was well worth it. This worked really well with a Spring application; with other setups your mileage may vary.
Maven should start an instance of the H2 database in-memory before doing any tests. In a Spring application, you can just specify your datasource with an H2 JDBC URL and it'll start automagically.
You can use Liquibase to run a set of XML scripts to set up your database schema, and then a separate file to populate them with test data (either by specifying different files when running Liquibase, or by using the context attribute of each changeSet). This can be done with Maven, or in Spring using a specific Liquibase bean.
From there you can test your application exactly as if it was a normal app. No need for mocking, and you get much more useful tests as a result. You may need to change your schema or otherwise work around SQL differences between H2 and your native RDBMS.
As an aside, I'm greatly in favour of these sorts of tests. In my experience mocking everything doesn't really gain you any interesting insights, and should be a last resort for when intra-build integration tests aren't possible. There are many that disagree with me though!
The question is what behavior do you need to unit test? If you mocked out the database then you've tested all the important logic. Your database adapter will either work or not work, which you can verify in integration/acceptance tests against a real database.
You can use DBUnit. It takes your current schema and you can easily mock your data.
Related
I'm using JPA to store my java objects in a database using javadb.
Now i've written JUnit tests to check whether the objects are correctly stored and removed etc. from the javadb.
The problem is that modifications to the database in previous tests impact later tests and, more importantly, obviously modify the database that i'm using for my application.
One solution i found was reversing the transaction for each test, but since several of the methods i'm testing already commit their transaction I don't think this would work for me.
I also thought about creating a backup by storing all the data in a file and restoring the database afterwards or making a created persistence.xml with a different jdbc.url value (that will somehow be used when i'm running the tests instead of the original) and creating a separate database.
But i've got no idea how to make either of those solutions work or if they are even good solutions.
So could anyone explain to me how to exactly go around avoiding modifications to the original database while running these tests?
I ended up just using maven with a seperate persistence.xml that configured a different javadb database purely for running tests as explained here.
I didn't use DBUnit as Alan Hay's comment suggested, because of time constraints, but this seems a valid option as well.
I'm looking for a simple way to test Hibernate HQL criteria queries. I've tried using IntelliJ's Hibernate Console support, but I've run into problems.
Is there a standalone tool that provides a simple way to test HQL queries? A simple console program that creates the session factory and executes a query passed as an argument would suffice.
You can use the H2 (JDBC in-memory) database, and jetty for your container, to create a container and context that will execute hibernate queries in the unit-test phase of your build (or from JUnit).
Using a console would be my first choice for just playing with HQL (eg Hibernate Tools for eclipse). But if that doesn't work, I would just use JUnit. My team uses that strategy to test the HQL queries that we use in production code, and occasionally to help write queries in the first place.
The test setup involves setting up an in-memory database (we use HSQLDB, but there's others). Insert data either with Hibernate or with raw SQL. Then configure a Hibernate SessionFactory to connect to it, and run your HQL.
We also use this to test other kinds of Hibernate settings or behaviors, and has the side benefit of being a full test suite on Hibernate for our purposes so that we can upgrade and have confidence that nothing we need has changed in an unexpected way.
I doubt it's possible to have such a tool as a separate app, you'll need to specify a hibernate configuration (which might be in Spring Context), and it should be able to find the classes and their HBM files. Moreover you might use different UserTypes or anything like that from other JARs, so I wouldn't even search for it.
For me the best tool is a unit testing framework + debugging facilities of your IDE - you can just stop at some point where you have a session created and do whatever you want in this mode. In IntelliJ for instance, aside of usual expressions, you can put code fragments during debugging which might help you with Criteria API.
Last time I had to do this kind of work I used DbUnit to test my data access layer in which I was using JPA 2.0 with Hibernate
You could try a JUnit approch.
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 an application where many "unit" tests use a real connection to an Oracle database during their execution.
As you can imagine, these tests take too much time to be executed, as they need to initialize some Spring contexts, and communicate to the Oracle instance. In addition to that, we have to manage complex mechanisms, such as transactions, in order to avoid database modifications after the test execution (even if we use usefull classes from Spring like AbstractAnnotationAwareTransactionalTests).
So my idea is to progressively replace this Oracle test instance by an in-memory database. I will use hsqldb or maybe better h2.
My question is to know what is the best approach to do that. My main concern is related to the construction of the in-memory database structure and insertion of reference data.
Of course, I can extract the database structure from Oracle, using some tools like SQL Developer or TOAD, and then modifying these scripts to adapt them to the hsqldb or h2 language. But I don't think that's the better approach.
In fact, I already did that on another project using hsqldb, but I have written manually all the scripts to create tables. Fortunately, I had only few tables to create. My main problem during this step was to "translate" the Oracle scripts used to create tables into the hsqldb language.
For example, a table created in Oracle using the following sql command:
CREATE TABLE FOOBAR (
SOME_ID NUMBER,
SOME_DATE DATE, -- Add primary key constraint
SOME_STATUS NUMBER,
SOME_FLAG NUMBER(1) DEFAULT 0 NOT NULL);
needed to be "translated" for hsqldb to:
CREATE TABLE FOOBAR (
SOME_ID NUMERIC,
SOME_DATE TIMESTAMP PRIMARY KEY,
SOME_STATUS NUMERIC,
SOME_FLAG INTEGER DEFAULT 0 NOT NULL);
In my current project, there are too many tables to do that manually...
So my questions:
What are the advices you can give me to achieve that?
Does h2 or hsqldb provide some tools to generate their scripts from an Oracle connection?
Technical information
Java 1.6, Spring 2.5, Oracle 10.g, Maven 2
Edit
Some information regarding my unit tests:
In the application where I used hsqldb, I had the following tests:
- Some "basic" unit tests, which have nothing to do with DB.
- For DAO testing, I used hsqldb to execute database manipulations, such as CRUD.
- Then, on the service layer, I used Mockito to mock my DAO objects, in order to focus on the service test and not the whole applications (i.e. service + dao + DB).
In my current application, we have the worst scenario: The DAO layer tests need an Oracle connection to be run. The services layer does not use (yet) any mock objects to simulate the DAO. So services tests also need an Oracle connection.
I am aware that mocks and in-memory database are two separates points, and I will address them as soon as possible. However, my first step is to try to remove the Oracle connection by an in-memory database, and then I will use my Mockito knowledges to enhance the tests.
Note that I also want to separate unit tests from integration tests. The latter will need an access to the Oracle database, to execute "real" tests, but my main concern (and this is the purpose of this question) is that almost all of my unit tests are not run in isolation today.
Use an in-memory / Java database for testing. This will ensure the tests are closer to the real world than if you try to 'abstract away' the database in your test. Probably such tests are also easier to write and maintain. On the other hand, what you probably do want to 'abstract away' in your tests is the UI, because UI testing is usually hard to automate.
The Oracle syntax you posted works well with the H2 database (I just tested it), so it seems H2 supports the Oracle syntax better than HSQLDB. Disclaimer: I'm one of the authors of H2. If something doesn't work, please post it on the H2 mailing list.
You should anyway have the DDL statements for the database in your version control system. You can use those scripts for testing as well. Possibly you also need to support multiple schema versions - in that case you could write version update scripts (alter table...). With a Java database you can test those as well.
By the way, you don't necessarily need to use the in-memory mode when using H2 or HSQLDB. Both databases are fast even if you persist the data. And they are easy to install (just a jar file) and need much less memory than Oracle.
Latest HSQLDB 2.0.1 supports ORACLE syntax for DUAL, ROWNUM, NEXTVAL and CURRVAL via a syntax compatibility flag, sql.syntax_ora=true. In the same manner, concatenation of a string with a NULL string and restrictions on NULL in UNIQUE constraints are handled with other flags. Most ORACLE functions such as TO_CHAR, TO_DATE, NVL etc. are already built in.
At the moment, to use simple ORACLE types such as NUMBER, you can use a type definition:
CREATE TYPE NUMBER AS NUMERIC
The next snapshot will allow NUMBER(N) and other aspects of ORACLE type compatibility when the flag is set.
Download from http://hsqldb.org/support/
[Update:] The snapshot issued on Oct 4 translates most Oracle specific types to ANSI SQL types. HSQLDB 2.0 also supports the ANSI SQL INTERVAL type and date / timestamp arithmetic the same way as Oracle.
What are your unit tests for?
If they test the proper working of DDLs and stored procedures then you should write the tests "closer" to Oracle: either without Java code or without Spring and other nice web interfaces at all focusing on the db.
If you want to test the application logic implemented in Java and Spring then you may use mock objects/database connection to make your tests independent of the database.
If you want to test the working as a whole (what is against the modular development and testing principle) then you may virtualize your database and test on that instance without having the risk of doing some nasty irreversible modifications.
As long as your tests clean up after themselves (as you already seem to know how to set up), there's nothing wrong with running tests against a real database instance. In fact it's the approach I usually prefer, because you'll be testing something as close to production as possible.
The incompatibilities seem small, but really end up biting back not so long afterwards. In a good case, you may get away with some nasty sql translation / extensive mockery. In bad cases, parts of the system will be just impossible to test, which I think is an unacceptable risk for business-critical systems.