Question

I have layered architecture in the project like Controller -> Service -> DAO. I want to write the JUnit test cases for service layer. Now as service layer will be internally calling DAO methods, why should I write different test cases for DAO layer as it is internally tested.

Some people say I need to mock DAO methods using mockito. Is it really required? Cant I directly use original code while testing service layer methods?

Was it helpful?

Solution

Provide one set of tests for your services, and a separate set of tests for the DAOs.

The DAO tests should be against a database, preferably an in-memory database. That's not just because it's easy to create it and tear it down in the test but because you will know it is yours and no one else is changing it. The DAO tests will test that your database mappings and SQL are right. You can use DBUnit to initialize the database with test data and to verify the contents of the database at the end of each test, so each test can run against a known dataset. With separate DAO tests if there are database-level problems those will be easier to distinguish, because you will see them in the DAO tests and not in the test for the services.

The services can be tested using mocks for the DAOs. Because the tests don't use a database they will execute faster (tests against a database run a lot slower, even using an in-memory database) and you can exercise a lot of different scenarios without slowing your tests down. The service layer is typically where most of your complexity will be so it will take more tests to cover it, it's much better if those tests can run quickly.

Typically you have DAOs with methods that do crud operations, and those methods get called over and over again in different ways in the services. When you limit database access to only the DAO tests you minimize the total amount of database access your tests need, and the tests run much faster.

What you talk about, having one set of tests that test all the way through (services and DAOs) against a database, is very tempting because a) it tests against real things all the way down, and b) it seems like it will be less work (also a lot of times the project doesn't have sufficient abstraction, you can't test things separately effectively, and there's no time to break things out). Lots of projects make the same decision for sensible reasons, and they all steer straight into the same tarpit trap of tests that take too long to run and which leave too many cases uncovered (because developers get discouraged about adding more test cases when their existing tests already take too long). Slow tests lead to bad code coverage and ineffective testing.

OTHER TIPS

In my opinion, you should avoid Mocks as much as you can. The reasons why to avoid Mocks are:

  • you have to make sure that your mocks are compliant with the contract defined by the interface of the DAOs you mock.
  • reading mock-tests is much more difficult than reading simple unit tests using real implementations. Hence it is much more likely your test may contain errors by itself or has logical flows. A good test is one which is simple to understand and to verify it is (likely to be) correct.

This does not mean, you should never use Mocks, but you should prefer real implementations as much as you can.

On the other side, whenever an implementation requires heavyweight implementations or resources like databases, JNDI or JMS you want to use Mocks. Otherwise you tests are always kind of integration tests, which require a heavyweight setup and slow down your test-suite.

My recommendation is to provide an in-memory implementation for each type requiring heavyweight resources like databases, JNDI, JMS etc. To ensure they are real alternatives, compliant with the contract, they have to pass the same tests as the real implementations. Hence, full test coverage for those implementations with the contract is mandatory!

From now on, you should be find using real implementations where every you need them. And for all the hard situations to test, like network errors, database connections or protocols, us Mocks. They are best in this cases, but should be reduced to those cases only in my opinion.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top