Saturday, April 6, 2013

JDBI Mockito Headaches

I've started using JDBI for my background jobs since it alleviates much of the pain of JDBC. So far it has been a good experience except that when I started writing unit tests I found that the author has placed the final modifier on all the bind methods, which makes it impossible to override for mocking. I looked at PowerMock (which performs tricks to mock final methods) but it produced inconsistent results; essentially it worked for the first invocation but failed on subsequent invocations. Instead of giving up on JDBI, I created an UpdateDelegate class with simply provides non-final bind methods and delegates to the JDBI class.


public class UpdateDelegate {
private Update delegate;
public UpdateDelegate(Update update) {
this.delegate = update;
}

public UpdateDelegate bindNull(String alias, int type) {
delegate.bindNull(alias, type);
return this;
}
public UpdateDelegate bind(String alias, Long value) {
delegate.bind(alias, value);
return this;
}
public UpdateDelegate bind(String alias, String value) {
delegate.bind(alias, value);
return this;
}

public UpdateDelegate bind(String alias, Float value) {
delegate.bind(alias, value);
return this;
}

public UpdateDelegate bind(String alias, Integer value) {
delegate.bind(alias, value);
return this;
}
public UpdateDelegate bind(String alias, Timestamp value) {
delegate.bind(alias, value);
return this;
}
public int execute() {
return delegate.execute();
}

In my test class I use Mockito to mock UpdateDelegate and apply the following stubbing, so the fluents work

private void applyWhens(UpdateDelegate updateDelegate) {
Mockito.when(updateDelegate.bind(Mockito.anyString(), Mockito.anyLong())).thenReturn(updateDelegate);
Mockito.when(updateDelegate.bind(Mockito.anyString(), Mockito.anyInt())).thenReturn(updateDelegate);
Mockito.when(updateDelegate.bind(Mockito.anyString(), Mockito.anyString())).thenReturn(updateDelegate);
Mockito.when(updateDelegate.bind(Mockito.anyString(), Mockito.anyFloat())).thenReturn(updateDelegate);
Mockito.when(updateDelegate.bind(Mockito.anyString(), Mockito.any(Timestamp.class))).thenReturn(updateDelegate);
Mockito.when(updateDelegate.bindNull(Mockito.anyString(), Mockito.anyInt())).thenReturn(updateDelegate);
}

Now I can verify, e.g.

Mockito.verify(updateDelegate).bind("total", 1000L);


All of this nonsense because of the final methods on bind, sheesh.