The Advisory Board Engineering Blog

EasyMock and JUnit anti-patterns


Bill Schneider

We use JUnit heavily at the Advisory Board to test our server-side components at the class and method level. This allows us to execute a wider variety of test scenarios more frequently than we could through end-to-end manual testing. 

With JUnit, we can isolate the class or method we want to test and invoke it directly with a set of inputs and assert that we get the expected outputs. Jenkins then runs these tests on every build, and the team gets email complaints when one of the tests fails. With manual testing, we would have to navigate through the UI to get to the part of the code we want and figure out how to construct test data in the DB to trigger it—more effort and less repeatable.

We also use EasyMock inside our unit tests to make it easier to test UI controllers/managed beans and business logic classes, with mock objects to stub out the persistence layer. This allows us to have true unit tests because they run quickly and don't touch the DB.

We can also use mocks for other components that are loosely coupled with the one under test in a particular unit test, so we don't have to set up all the prerequisites for some other component when the class we're trying to test just calls one method on it to get a list of something.

As useful as EasyMock is, though, it may make tests harder to write and maintain if not used properly. One anti-pattern that popped up early in the learning process was mocking data objects, or mocking an object that is just a container for data (e.g. a bean or a map) where an actual object could have worked equally well and would have been more readable.

 In other words:

would be much cleaner as simply:

 

Another anti-pattern that popped up is "copy-paste monolithic controller test."  Suppose we have a controller whose method body calls a sequence of actions:

In some cases, we would test the conditions in step1, step2, etc. by testing the whole controller method. Then, when we added another path through step1, we would test the whole controller again—even though most of the code becomes setting up the dependencies for the other step2 and step3 methods that were already tested somewhere else.

We decided to have a controller test that doesn't test the logic in the individual subroutines. That test is sufficient to ensure that the individual steps are called in sequence. Then, the logic in each of the individual methods is tested directly, in isolation. This limits the amount of copy-paste. It does require us to use the default access modifier (rather than private), so the methods are visible from our tests.


Bill is a lead architect at The Advisory Board Company. Since joining in 2006, he has been involved in the development of new performance technologies products, including Surgical Profitability Compass.

 



Join the discussion

Please log in to comment.
Close

Forgot your password?


Not an Advisory Board Member? Click here to register

Close

Members please Log In

LOG IN

Forgot your password?


Not an Advisory Board Member? Click here to register