Thursday, March 2, 2017
Mock Testing with Groovy
Mock Testing with Groovy
Mock classes enable developers to quickly write unit tests that would otherwise require integration tests because of the need for a database, web container, or servlet container. Using mock classes helps to test a class in isolation and enables rapid feedback. Its not ideal to have a project with only integration tests and no unit tests. Mock classes enable unit testing that otherwise would be impossible.
So how does one create a mock class? Well, there definitely is not a shortage of mock frameworks: EasyMock, jMock, Gmock, MockFor and StubFor. You can always just create your own mock class in your test suite (which I have done in the past when in a pinch). But in my opinion these solutions lack one thing: the ability to quickly create a simple mock that when called returns what I want. To many of the mock frameworks force you to jump through hoops and call methods like expect(), replay(), verify(). What I want is the ability to define a mock class in a single line and inject it myself.
I thought MockFor and StubFor would be the solution, but the documentation is lacking and I havent figured out how to make it work for me. Ideally I would like to say something like:
def mock = new MockFor(ICarDao.class) {
getCar: {return new Car(color: "blue")}
}
Then MockFor would mock out the remaining methods of ICarDao and now I have a mock class that implements the getCars method that when called by the Class Under Test (CUT) will return a single Car model. But MockFor doesnt work like this and neither do any of the mock frameworks to my knowledge.There is hope however. Below you can read about 2 alternatives: groovys metaClass and as keyword. Both require the use of groovy in your tests. If you havent switched to using groovy to write tests yet, even for Java, then its time to start now. There is no other framework or library that can make you more productive when writing tests. Its an instant boost.
Groovys metaClass
As seen in this example, groovys meta programming is very powerful. In that post I show how one can essentially mock out Thread.startDaemon() by using Thread.metaClass.static.startDaemon. Groovys meta programming is very powerful as seen by its heavy use in grails to make things simple. But it doesnt work in all cases.
Groovys as keyword
Using metaClass is by far the easiest and my favorite way to create a mock class. However, this didnt work for me in my recent attempt to write some unit tests for a Java Manager class that used spring to inject a DAO that the manager used. It didnt work I believe because my Manager class never created the concrete DAO. It defines some getters and setters and expects spring to inject the concrete class. Because of this metaClass didnt work (bummer). So I did a lot of research to come up with a competitive alternative: groovys as keyword.
Lets start by defining the Manager class:
public class CarManager {
private ICarDao dao;
public void startCar() {
Car car = dao.getCar();
.......
}
public CarManager setCarDao(ICarDao dao) {
this.dao = dao;
return this;
}
}
Now to test this using mock classes and the as keyword all you need to do is this:This uses a map and the as keyword to implement an interface. Here the key is the name of the method to mock and the value is a closure of what you want returned when called. And there is no need to define all the methods of the interface, just the ones you want to mock out.class CarManagerTest extends GroovyTestCase {
def void test_start_car() {
ICarDao mock = [
getCar: {return new Car(color: "blue")}
] as ICarDao;
def cut = new CarManager().setCarDao(mock);
}
}
To me, metaClass and the as keyword are much cleaner and simpler compared to the current mock frameworks. At least for this type of testing. Those frameworks might be perfectly useful for other types of testing, I just havent ran into them yet.
Available link for download