1

We're using MyBatis (3.0.5) as our or-mapping tool (and I don't have any say-so over that!).

I've created a Response object that, through MyBatis, mapped to our [responses] database table (we use PostgreSQL).

Actually, the ormapping structure we use is as follows:

  • ResponseMapper.xml - this is the XML file where the PSQL queries are defined and mapped to the ResponseMapper.java** class and its methods
  • ReponseMapper.java - An interface used by MyBatis for executing the queries defined in the XML file (above)
  • ResponseDAO.java - An interface used for DI purposes (we use Spring)
  • ResponseDAOImpl.java - A concrete implementation of ResponseDAO that actually calls ResponseMapper methods; we use Spring to inject instances of this class into our application

So, to INSERT a new [responses] record into PostgreSQL, the code looks like this from the invoking component:

@Autowired
private ResponseDAO response;

public void doStuff()
{
    int action = getAction();

    response.setAction(action);

    response.insert();
}

This set up works beautifully for us. However I am now trying to write a set of JUnit tests for the ResponseDAOImpl class, and I want to make sure that it is correctly executing queries to our PostgreSQL database.

As far as I can tell, there is no way to "mock" an entire database. So my only option (seemingly) is to have the test method(s) execute a query, check for success, and then roll it back regardless.

MyBatis doesn't seem to support this kind of rollback feature. I found this post off the mybatis-user mailing list on Old Nabble, but the poster was using Guice and his/her question seemed to be more about rolling back transactions through Guice.

If MyBatis doesn't support transactions/rollbacks (does it?!?!), then it seems like my only repireve would be if the PostgreSQL-JDBC driver supports these. I guess I could then try to configure my test methods so that they run the ResponseDAO.insert() method, and then manually try to rollback the transaction directly through the driver (sans MyBatis).

Does SO have any experience with this? Code samples? Tips? Best practices? Thanks in advance!

IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756

2 Answers2

0

Not sure this is what you need, but org.apache.ibatis.session.SqlSession class has rollback() method which can be used to rollback.

Another approach is to use getConnection() method from the same class which will return javax.sql.Connection javax.sql.Connection class which also has commit() and rollback() methods.

Hope it helps. Remis B

Remis B
  • 365
  • 3
  • 11
  • You know what, I didn't even think about that. I can get access to the SqlSessionFactory through my application context (supplied by Spring). From there I can get the SqlSession and the Connection, which like you pointed out, gives me access to Savepoints, commit() and rollback(). Thanks Remis! – IAmYourFaja Dec 20 '11 at 21:07
0

MyBatis allows rollbacks when working with an "SqlSession", the thing is your using the spring dependency injection piece, which automatically commits your transaction when the method completes.

You have a few options, among them

  1. Inject a Mock of your dependencies. There is some rocking libraries to help with this. Like Mockito, here is a good question on Spring Mockito stuff. This will test your business logic in your java, but not your actual queries.

  2. Commit your queries, and delete your data after the test runs. This is the approach we took, because it tests our database as well. You would obviously need a test instance of your database, which some people don't have.

  3. You could try to provide your own test bindings for the classes that do the automatic commit in the MyBatis Spring Integration and override there behavior so that in the test environment the behavior is to rollback the query instead of committing. A similar approach was use in the Guice integration, and it is described here.

Community
  • 1
  • 1
Andy
  • 8,841
  • 8
  • 45
  • 68
  • Andy, can you please look at Remis B's answer, and my follow-up comment? Would that solution not work? What if my test method first obtained the SqlSession from the SqlSessionFactoryBean, and setAutoCommit(false), obtained a Savepoint, executed the query, and then rolledback to the Savepoint? Does Spring still override this behavior?!? – IAmYourFaja Dec 20 '11 at 21:08
  • Are you injecting mappers? If so I think Spring will still open a new SqlSession for the mapper calls. I'm really more familiar with the Guice stuff, but the docs[1] make me think the mapper runs its own sql session. http://code.google.com/p/mybatis/downloads/detail?name=mybatis-spring-1.0.2-reference.pdf – Andy Dec 20 '11 at 21:23