Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do we write unit tests for methods which involves connection with DB?

I have been having a query regarding writing unit tests for web methods which actually communicates with a database and returns some value.

Say for example I have a web service named "StudentInfoService". That web serivces provides a API "getStudentInfo(studentid)"

Here is some sample snippet

public class StudentInfoService
{
    public StudentInfo getStudentInfo(long studentId) {
            //Communicates with DB and creates
            // StudentInfo object with necessary information
            // and returns it to the caller.
    }
}

How do we actually write unit tests for this method getStudentInfo? Generally how do we write unit tests for methods which involves a connection with a resource(Database, Files, JNDI, etc...)?

like image 785
Sundar Annamalai Avatar asked Jul 17 '11 12:07

Sundar Annamalai


2 Answers

Firstly, the class StudentInfoService in your example is not testable, or atleast not easily. This is for a very simple reason - there is no way to pass in a database connection object to the class, at least not in the method that you've listed.

Making the class testable would require you to build your class in the following manner:

public class StudentInfoService
{
    private Connection conn;

    public StudentInfoService(Connection conn)
    {
        this.conn = conn;
    }

    public StudentInfo getStudentInfo(long studentId) {
            //Uses the conn object to communicate with DB and creates
            // StudentInfo object with necessary information
            // and returns it to the caller.
    }
}

The above code allows for dependency injection via the constructor. You may use setter injection instead of constructor injection, if that is more suitable, but it usually isn't for DAO/Repository classes, as the class cannot be considered fully formed, without a connection.

Dependency injection would allow your test cases to create a connection to a database (which is a collaborator to your class/system under test) instead of getting the class/system itself to create the collaborator objects. In simpler words, you are decoupling the mechanism of establishing database connections from your class. If your class was previously looking up a JNDI datasource and then creating a connection, then it would have been untestable, unless you deployed it to a container using Apache Cactus or a similar framework like Arquillian, or if you used an embedded container. By isolating the concern of creating the connection from the class, you are now free to create connections in your unit tests outside the class and provide them to the class on a as-needed basis, allowing you to run tests inside a Java SE environment.

This would enable you to use a database-oriented unit testing framework like DbUnit, which would allow you to setup the database in a known state before every test, then pass in the connection to the StudentInfoService class, and then assert the state of the class (and also the collaborator, i.e. the database) after the test.

It must be emphasized that when you unit test your classes, your classes alone must be the only systems under test. Items like connections and datasources are mere collaborators that could and ought to be mocked. Some unit tests would use in-memory databases like H2, HSQL, or Derby for unit-tests and use the production-equivalent installations of databases for integration and functional testing.

like image 55
Vineet Reynolds Avatar answered Oct 21 '22 04:10

Vineet Reynolds


Try to use http://www.dbunit.org/intro.html.

Main idea - make a stub database with known dataset to run your tests and assert results. You will need to reload the dataset before runs to restore initial state.

like image 44
ya_pulser Avatar answered Oct 21 '22 03:10

ya_pulser