mybatis 3 unit testing best practice?

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

mybatis 3 unit testing best practice?

Andy Law
All,

Under iBatis 2, it was possible to separately test the sqlMapClient,
the DAO objects and the DAO consumers using Mocks where necessary.
I've spent this afternoon reading the MyBatis 3 user guide and several
blog and mailing list threads and from what I understand right now,
that's not possible (at least not easily) with the new style
sqlSession to Mapper design.

I note at the end of http://tinyurl.com/68ayev6, Clinton suggests that
all tests should hit the database anyway. Is this accepted best
practice now (at least for Clinton :o}) or have I missed a trick
somewhere about other ways to design and run tests across these
objects.

Later,

Andy
Reply | Threaded
Open this post in threaded view
|

Re: mybatis 3 unit testing best practice?

Larry Meadors
I do both. :)

I test the mappers in a transaction (which gets rolled back after the
test completes - pass or fail).

I test classes that USE the mappers using mocks - makes it WAY easier
to test specific data scenarios.

Larry
Reply | Threaded
Open this post in threaded view
|

Re: mybatis 3 unit testing best practice?

Andy Law


On Mar 11, 5:42 pm, Larry Meadors <[hidden email]> wrote:
> I do both. :)
>

I didn't explain myself properly :o{

My iBatis 2 scenario has 3 points of test, 2 in the DAO layer and then
the layers that *use* the DAOs to make 3).

I could test that the DAOs were making the correct calls against the
sqlMapClient by Mocking the sqlMapClient. I could do that in the
absence of a database. I could then separately test the sqlMapClient
queries. Seems that the option to do those as separate operations is
gone in myBatis3 because of the change in architecture and the
generation of the Mapper classes.


> I test the mappers in a transaction (which gets rolled back after the
> test completes - pass or fail).

Just out of curiosity, do you put your transactions in the tests or in
the test harness hooks (@Before, @After)


>
> I test classes that USE the mappers using mocks - makes it WAY easier
> to test specific data scenarios.

Indeed.

Later,

Andy
Reply | Threaded
Open this post in threaded view
|

Re: mybatis 3 unit testing best practice?

Larry Meadors
On Mon, Mar 14, 2011 at 3:59 AM, Andy Law <[hidden email]> wrote:
> Just out of curiosity, do you put your transactions in the tests or in
> the test harness hooks (@Before, @After)

I use the hooks in a superclass that my tests extend - the @Before
also flushes the cache.

That way, the tests themselves are super simple - no need to clutter
them with that stuff - just extend MapperTestBase.

I have found that it's REALLY useful to use that test base for
"service" classes that aggregate mapper calls and do more complex
operations.

I also add little helper methods in those to help set up required data
- so if I have a test that needs an Address that requires a User, I
can do this:

User user = createUser();
Address address = createAddress(user);
// test away with a valid database user and address

Larry
Reply | Threaded
Open this post in threaded view
|

Re: mybatis 3 unit testing best practice?

Andy Law


On Mar 14, 10:54 am, Larry Meadors <[hidden email]> wrote:
> On Mon, Mar 14, 2011 at 3:59 AM, Andy Law <[hidden email]> wrote:
> > Just out of curiosity, do you put your transactions in the tests or in
> > the test harness hooks (@Before, @After)
>
> I use the hooks in a superclass that my tests extend - the @Before
> also flushes the cache.
>
> That way, the tests themselves are super simple - no need to clutter
> them with that stuff - just extend MapperTestBase.

That was the pattern that I was heading towards. I had not thought
about the cache though - good shout.


>
> I have found that it's REALLY useful to use that test base for
> "service" classes that aggregate mapper calls and do more complex
> operations.
>
> I also add little helper methods in those to help set up required data
> - so if I have a test that needs an Address that requires a User, I
> can do this:
>
> User user = createUser();
> Address address = createAddress(user);
> // test away with a valid database user and address
>


Not sure what you are saying here - does your base class call a
routine that you subclasses implement or do you use Annotations in
your subclasses?

Is there a tutorial/blog/resource that covers this stuff for v3?

Later,

Andy
Reply | Threaded
Open this post in threaded view
|

Re: mybatis 3 unit testing best practice?

Larry Meadors
On Mon, Mar 14, 2011 at 5:36 AM, Andy Law <[hidden email]> wrote:
> Not sure what you are saying here - does your base class call a
> routine that you subclasses implement or do you use Annotations in
> your subclasses?


The @Before and @After annotations run in a consistent order - so my
superclass starts and ends the transaction for all of the tests that
extend it. If you have a @Before annotated method in your superclass,
that runs before any @Before annotated methods in your test classes.
Make sense?


> Is there a tutorial/blog/resource that covers this stuff for v3?


Not that I know of, no.


Larry
Reply | Threaded
Open this post in threaded view
|

Re: mybatis 3 unit testing best practice?

Rafael Ponte
In reply to this post by Andy Law
Hi Andy,

The main problem about writing unit tests on third-party APIs (like MyIBatis or even Hibernate) is that normally you turn out having brittle tests. When you're testing the persistence layer your goal should be testing the result of that layer but not the structure of the implementation.

So, IMHO, the best way to test the persistence layer should be through integration tests.

On Fri, Mar 11, 2011 at 2:03 PM, Andy Law <[hidden email]> wrote:
All,

Under iBatis 2, it was possible to separately test the sqlMapClient,
the DAO objects and the DAO consumers using Mocks where necessary.
I've spent this afternoon reading the MyBatis 3 user guide and several
blog and mailing list threads and from what I understand right now,
that's not possible (at least not easily) with the new style
sqlSession to Mapper design.

I note at the end of http://tinyurl.com/68ayev6, Clinton suggests that
all tests should hit the database anyway. Is this accepted best
practice now (at least for Clinton :o}) or have I missed a trick
somewhere about other ways to design and run tests across these
objects.

Later,

Andy



--
Rafael Ponte
http://www.rponte.com.br
Reply | Threaded
Open this post in threaded view
|

Re: mybatis 3 unit testing best practice?

Clinton Begin
Administrator
In reply to this post by Andy Law
This is a common confusion, and a discussion we've even had on the MyBatis team. 

Here's the thing:

* Mappers are not DAOs... they are a better way to call mapped statements.  They are a replacement for:
    SomeClass someVariable = (SomeClass) sqlMapClient.executeQuery("somestatement",param);

* There is nothing to test inside of a Mapper.  Literally, if one works, they will all work (every single mapper method call executes the exact same code block).  It's literally just a reflective call from a method name to a statement name.  At most you could test that you were calling the right statement, but the best way to do that is to hit the database, as otherwise you'd dig into the guts of MyBatis only to prove half of the point (it's not a complete test).

* Mappers are interfaces.  Interfaces have no code to test (until JDK 1.7/8 with NVI, which you will be able to test other ways).

There are only 2 things to test in iBATIS 2.x and only 2 things to test in MyBatis 3.  But in MyBatis 3 there are two ways you can call those two things... mapper interfaces, or directly against the SqlSession (similar to iBATIS 2).  

In both cases you can choose to use a DAO framework such as the deprecated iBATIS DAO framework, or Spring DAO etc.  This would give you the 3rd level that would allow you to test combinations of calls to Mappers via a DAO (e.g. a DAO method may consist of an insert of an Order and LineItems -- two mapper calls, maybe with a bit of testable validation thrown in).

Cheers,
Clinton  





On Fri, Mar 11, 2011 at 10:03 AM, Andy Law <[hidden email]> wrote:
All,

Under iBatis 2, it was possible to separately test the sqlMapClient,
the DAO objects and the DAO consumers using Mocks where necessary.
I've spent this afternoon reading the MyBatis 3 user guide and several
blog and mailing list threads and from what I understand right now,
that's not possible (at least not easily) with the new style
sqlSession to Mapper design.

I note at the end of http://tinyurl.com/68ayev6, Clinton suggests that
all tests should hit the database anyway. Is this accepted best
practice now (at least for Clinton :o}) or have I missed a trick
somewhere about other ways to design and run tests across these
objects.

Later,

Andy

Reply | Threaded
Open this post in threaded view
|

Re: mybatis 3 unit testing best practice?

Andy Law
Clinton,


On Mar 14, 4:16 pm, Clinton Begin <[hidden email]> wrote:
> This is a common confusion, and a discussion we've even had on the MyBatis
> team.
>
> Here's the thing:
>
> * Mappers are not DAOs... they are a better way to call mapped statements.
>  They are a replacement for:
>     SomeClass someVariable = (SomeClass)
> sqlMapClient.executeQuery("somestatement",param);

I think that has been this afternoon's "Aha! moment", a conclusion
that I reached just about an hour ago whilst tracking down how to deal
with "like" statements using the PetStore code as an example!

Although my DAO code interfaces (I have more than one datasource, only
one of which is an honest-to-goodness relational database) will bear
an uncanny resemblance to my Mapper interfaces.

Later,

Andy