DAO Unit testing

2020-02-17 08:43发布

问题:

I have been looking at EasyMock and tutorials/examples around using it for Unit Testing DAO classes, for an "outside container" test. However, I think most of them talk about testing the Service Layer instead, mocking the DAO class. I am a bit confused, is it really how you Unit Test the DAO layer?

Some would say that the tests interacting with DB & EJBs are actually Integration tests and not Unit tests but then how would you know if your SQL is correct (assuming no ORM) and your DAO inserts/queries the right data from your real (read, local database which is similar to that in production) database?

I read that DBUnit is a solution for such a situation. But my question is about using a framework like DBUnit "outside container". What if the DAO depends on some EJBs, how do we handle the transactions, what happens if there are triggers that update other tables on your inserts?

What is the best way to Unit Test only the DAOs with such dependencies?

回答1:

Personally, I unit test DAOs by hitting some sort of test database, preferable the same type of database (not the SAME database, obviously) that your app uses in production.

I think if you do that, the test is more of an integration test, because it has a dependency on a running database. This approach has the benefit in that it is as close as possible to your running production environment. It has the downsides that you need test configuration, you need a running test database (either local to your machine or somewhere in your environment) and the tests can take longer to run. You also need to be sure to rollback the test data after tests execute.

Once DAOs are tested, definitely mock them to unit test your services.



回答2:

Typically with DAOs the idea is to have a minimal wrapper around data-access code, so there's nothing there to test except for the mapping to the database, and unit tests with mocks are useless. If there is actually logic in the DAO worth testing with mocks, then an argument could be made that you're misusing the DAO pattern and that the logic should be in a service.

For testing the mapping to the database DBUnit is useful because it allows you to specify a starting dataset before the test so your test starts from a known state, and it allows you to specify what the ending state of the data should be, so you don't have to write a lot of unit test code asserting what is there is what is expected.

Ideally if you have a tool like Hibernate that abstracts the database away you can get by with using an in-memory database like H2 or HSQLDB, so your tests run faster and there's no database to create. If you do have to use a real database make sure your tests have it to themselves so they can create and delete data without impacting or being impacted by other processes. In practice having a database to yourself, both locally and in CI environments, is unlikely and using the in-memory database is much more practical.



回答3:

Complementing on Koya anwers, you can use HSQLDB for DAO testing. I imagine you have use Spring and Hibernate in your project. You would need separate configurations files to point for the HSQLDB, you would need to insert data prior to execute the tests. There are some limitations to what you can do with HSQLDB, but it is OK for general use as queries and joins. With this solution can be used in a continous environment , such as jenkins. Integration tests could use the HSQLDB , so this part is not mocked.



回答4:

I am using HSQLDB for Dao and Service API testing. The performance is good and it supports transactions too. I am not using EJB. I use Hibernate.

There are some issues that I am aware of that running the tests on a different database may mask some of the supported database issues. But I think such issues should be caught in the smoke & acceptance tests.

regards, Koya



回答5:

I ultimately settled for writing the Unit tests that can run outside the container, with a living database and for transactional support uses a standalone transaction manager (Bitronix), I am able to rollback also. I guess this doesn't make the test Pure Unit tests still...Would love to hear your opinion folks on this approach.