Stuff about software development, agile and testing

Friday, November 28, 2008

Thou shall not access network resources from unit test

Currently I am working on a tool called Verde, this is an automated characterization testing tool targeted for all Java legacy applications out in the wild.
One of the key feature of this tool is it can generate characterization tests with mocks meaning if we want we can generate Junit test cases by mocking database access or network access. Yeah it is cool.

As part of our integration test suite of Verde we have few end-to-end tests that generate test cases with mocks from sample application and run them to verify that everything is working, as they should be.

Recently one of our developer noticed that generated tests are no longer generating correct mock expectations. This must be because of some changes we made in our code but the crazy part is our integration tests never failed. In spite of wrong expectations our tests are still running fine because without mocks our generated tests are hitting the actual network resource and asserting the result received over the network. So from outside everything looked fine and worked fine too. Now this is an interesting problem, we cannot disable network connection because some tests are expected to use external resources. What do we do?

SecurityManager is for reuse.

Without going into details of how Security Manager works in Java, java.security.SecurityManager defines quite a few check methods for various operations like file read/write, print job, network access etc. The behavior of these check methods is very simple, if allowed nothing happens but when denied these methods are suppose to throw SecurityException.
So to tackle this problem we created a custom security manager to block network access. First we overridden all the check methods with do nothing implementation. This means that you are allowing all the access or granting all the permissions. Then we did something like following.



@Override
public void checkConnect(String host, int port) {
throw new SecurityException("Not allowed to access network connection, make sure all the dependencies are mocked out");
}

@Override
public void checkConnect(String host, int port, Object context) {
throw new SecurityException("Not allowed to access network connection, make sure all the dependencies are mocked out");
}

We are throwing SecurityException from couple of check methods related to network access. What it means is now when test will try to access network it will get security exception, and the test will fail. That’s it. Maybe oneday you might find this trick useful.

Oh don't forget to specify your custom security manager using –Djava.security.manager when running the tests.

Labels