Passing mock created with Groovy's MockFor as reference
I am trying to augment existing Java project with some Groovy goodness, starting with tests. So, let's say I have ServiceA (Java class) that depends on ServiceB (another Java class); it is passed as a reference in constructor:
public class ServiceA {
private ServiceB serviceB;
public ServiceA(ServiceB seviceB){
this.serviceB = serviceB;
}
public boolean doSomeWork(){
//some logic
return serviceB.doMoreWork();
}
}
Let's assume that serviceB.doMoreWork() returns true
.
In order to test ServiceA I want to mock ServiceB using MockFor:开发者_高级运维
@Test
void testDoSomeWork(){
def mocker = new MockFor(ServiceB) //1 create the Mock support
mocker.demand.doMoreWork(2){ //2 twice for this demonstration
false //3 return other value than in real code
}
mocker.use {
def mockServiceB = new ServiceB() //4 creates mock instead of real one
assert !mockServiceB.doMoreWork() //5 that's good!
def serviceA = new ServiceA(mockServiceB)
assert !serviceA.doSomeWork() //6 that fails! Real implementation called!
}
}
As you can see, the same object acts as mock in #5 and as real object in #6. I assume it has something to do with the fact that it is Java Object, not GoovyObject. What gives?
Thanks!
Baruch.
1) The following understanding is wrong:
def mockServiceB = new ServiceB() //4 creates mock instead of real one
You are not creating mock here. You are creating the real object. It's the method dispatch that Groovy routes differently.
2) In the code below, Groovy takes care of routing your doMoreWork() call to mock version because "new MockFor(ServiceB).demand.doMoreWork" gives Groovy the information that there is a stubbed implementation of doMoreWork()
def mocker = new MockFor(ServiceB) mocker.use { mockServiceB.doMoreWork() }
So, the above magic works when mockServiceB.doMoreWork() call is made from Groovy.
When the same call is made from Java, it does not go through Groovy's MOP infrastructure, so it goes directly to the real implementation of doMoreWork()
Remember: for MockFor, Groovy does not do any bytecode instrumentation, etc so that the modified class is visible in Java as well.
精彩评论