This week's book giveaway is in the Java 8 forum.
We're giving away four copies of Java 8 in Action and have Raoul-Gabriel Urma, Mario Fusco, and Alan Mycroft on-line!
See this thread for details.
The moose likes Testing and the fly likes Non J2EE transactional management in Java Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Java 8 in Action this week in the Java 8 forum!
JavaRanch » Java Forums » Engineering » Testing
Bookmark "Non J2EE transactional management in Java" Watch "Non J2EE transactional management in Java" New topic
Author

Non J2EE transactional management in Java

kartik krishnan
Ranch Hand

Joined: Nov 19, 2006
Posts: 63
Hi Jdbc Gurus,

I have a dao class that does crud operations on a postgressql database. Some of the queries are plain prepared statements while others are callable statements. The tables that I am accessing are related to one another by standard foreign key/unique key constraints.

I want to write unit tests for my dao classes. If I need to test my method that inserts into a database, I would have to do a clean delete after the insert is done and assertions are complete. This is tricky and can go wrong given the relationship between the table and because some of the logic is executed by stored procedures. If the queries fail, then I will be left with stale and incorrect data.

What I would like to do is the following:

My unit tests would be transactional. Within the boundaries of the transaction, I could call the dao crud methods, validate my assertions and roll back the changes to a prior known state without fail after my tests have been executed. It does not matter if my tests have succeeded or failed.

I know that servlet containers provide an implementation of JTA that could be used for transactional management, but since the unit tests are to be executed outside of the servlet container, I would like to use an implementation (open source) that could be used for transactional management. I know Spring framework has transaction management for unit tests, but we don't use Spring in our application and it is not feasible for create an Application Context for merely testing purposes.

Are there any open source JTA implementations or any other transactional management tools that are available that any one knows of that could be used outside of any servlet containers for purposes of unit testing? Any assistance would be appreciated.
Jan Cumps
Bartender

Joined: Dec 20, 2006
Posts: 2477
    
    7

Hmm, never thought about this option for testing. Might work if your test database can manage big transactions.

We usually avoid actually accessing a database while unit testing (see loads of evidence on the ranch and web).
Have you thought about using mock objects? You will probably get good answers on database/dao related testing in the Test forum.

OCUP UML fundamental and ITIL foundation
youtube channel
Scott Selikoff
Saloon Keeper

Joined: Oct 23, 2005
Posts: 3697
    
    5

I've been in this situation before, and what you need to know first off is that any unit test that involves a database, is not a unit test. Unit tests, the true meaning of them anyway, is a test that's completely, 100%, isolated from outside interactions.

In short, you can write JUnit test cases (not all JUnit tests are unit tests, nor do they need to be) that access a database but they are painful to write, at best, because you need to setup test data. Often times, I've used a JUnit's setUp/tearDown methods to setup database data, but its not for the faint of heart since the ability to screw things up is high, especially if your test case fail. At the very least, such a thing should never be run on a production database.

I'm guessing you have a business requirement (boss perhaps?) that is asking for unit tests of database-related code (often is the case). You have 4 choices:
  • 1. Try to get out of it by explaining that database/transactional test cases are not unit tests, but integration/system testing.
  • 2. Write JUnit tests that setup test data in the database before/after the test has been run
  • 3. Use a tool to fake a database specifically made for testing. Believe it or not such tools do exist, although they can be cumbersome to use. I once used this product for testing and simulating a database: Agitator
  • 4. Rewrite your classes so that all the 'important' business logic is in non-database related functions that can be tested as a unit. Systems that use object-relational mapping tools adapt naturally to this pattern.


  • My Blog: Down Home Country Coding with Scott Selikoff
    kartik krishnan
    Ranch Hand

    Joined: Nov 19, 2006
    Posts: 63
    @Jan - We use mock objects for testing a class in isolation. That is fine with us.

    In our application, quite a bit of business logic is database driven. We need to test to test CRUD operations.

    @Scott My answers are given below:




    Post Today 10:36:05 AM Subject: Non J2EE transactional management in Java
    I've been in this situation before, and what you need to know first off is that any unit test that involves a database, is not a unit test. Unit tests, the true meaning of them anyway, is a test that's completely, 100%, isolated from outside interactions.

    In short, you can write JUnit test cases (not all JUnit tests are unit tests, nor do they need to be) that access a database but they are painful to write, at best, because you need to setup test data. Often times, I've used a JUnit's setUp/tearDown methods to setup database data, but its not for the faint of heart since the ability to screw things up is high, especially if your test case fail. At the very least, such a thing should never be run on a production database.

    I'm guessing you have a business requirement (boss perhaps?) that is asking for unit tests of database-related code (often is the case). You have 4 choices:
    # 1. Try to get out of it by explaining that database/transactional test cases are not unit tests, but integration/system testing.

    We need to write integration tests so we need to write tests to test end to end flow. I have mocked connection and callable statement interfaces for unit testing the dao layer. But I still need to verify that stored procedure query or prepared statement signature has been implemented correctly in my Java code.

    # 2. Write JUnit tests that setup test data in the database before/after the test has been run

    This is root of the problem. I am not sure how to do this. Ideally the data in the database would be restored to a known state after the test execution and the states before and after the execution would exactly match. So after an insert query (say), I need to be able to rollback to a previous known state.

    # 3. Use a tool to fake a database specifically made for testing. Believe it or not such tools do exist, although they can be cumbersome to use. I once used this product for testing and simulating a database: Agitator

    My boss is not interested
    # 4. Rewrite your classes so that all the 'important' business logic is in non-database related functions that can be tested as a unit. Systems that use object-relational mapping tools adapt naturally to this pattern.

    For our project, this is impossible, as this application is legacy app and we have been implementing business logic in db for the past
    Scott Selikoff
    Saloon Keeper

    Joined: Oct 23, 2005
    Posts: 3697
        
        5

    kartik krishnan wrote:This is root of the problem. I am not sure how to do this. Ideally the data in the database would be restored to a known state after the test execution and the states before and after the execution would exactly match. So after an insert query (say), I need to be able to rollback to a previous known state.


    As I said, its not for the faint of heart. If your boss truly wants the states to be identical, then you could setup a backup/restore database utility by hand and/or accomplish the same via JDBC. In short, the code to test to your logic may be more complicated than the code your testing. There's no simple answer, if your boss wants it this way then your stuck recreating the database on every test.

    The only advice I can offer is try to go into the office with the philosophy "Well if I have time to write test code, I probably have time to work on something else". After all, its been my experience 99 out of a 100 something comes up before you can finish test code.

    As a side note... the real problem with this type of test is that databases are complex, transactional environments in which you have very little control over whats going on. For example, how do you test concurrency when a database may not execute items in the order you want? Also, if you're not recreating the entire database (say adding/deleting rows of a table instead), you have no control over what the database may be doing with the table or if someone else is accessing it. In short, databases are not single-threaded and unit tests on anything that is not single-threaded and you don't control is non-trivial at best, mind-numbing at worst.
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Non J2EE transactional management in Java
     
    Similar Threads
    Seeking ideas for the design of a JTA/XA transaction test
    Implementing Hibernate on legacy system
    Forcing a BatchUpdateException
    Hibernate Template not inserting data into the DB
    Data Access Objects: static methods