问题
I'm wondering how I can mock some private variable in a class with Groovy/Spock. Let's say we have this code:
public class Car {
private Engine engine;
public void drive(){
System.out.println("test");
if (engine.isState()) {
// Do something
} else {
// Do something
}
}
}
In Mockito I can write:
@Mock
private Engine engine;
@InjectMocks
private Car car = new Car();
@Test
public void drive() {
when(engine.isState()).thenReturn(true);
car.drive();
}
But I don't know how to do the same in Spock. What is the equivalent of @InjectMocks
in Spock?
回答1:
This is more a Groovy than a Spock question. In Groovy you can just call a constructor naming the private member and thus inject it. But this is ugly, you should rather refactor for testability via dependency injection as Tim Yates already said. But for what it is worth, here is how you can (but shouldn't) do it:
package de.scrum_master.stackoverflow;
public class Engine {
private boolean state;
public boolean isState() {
return state;
}
}
package de.scrum_master.stackoverflow;
public class Car {
private Engine engine;
public void drive(){
System.out.println("driving");
if(engine.isState()) {
System.out.println("true state");
} else {
System.out.println("false state");
}
}
}
package de.scrum_master.stackoverflow
import spock.lang.Specification
class CarTest extends Specification {
def "Default engine state"() {
given:
def engine = Mock(Engine)
def car = new Car(engine: engine)
when:
car.drive()
then:
true
}
def "Changed engine state"() {
given:
def engine = Mock(Engine) {
isState() >> true
}
def car = new Car(engine: engine)
when:
car.drive()
then:
true
}
}
BTW, then: true
is because your method returns void
and I don't know which other things you want to check.
The test is green and the console log looks like this:
driving
false state
driving
true state
回答2:
I'd suggest to put the Engine
into the car when it is constructed:
public class Car {
private final Engine engine;
public Car(final Engine engine) {
this.engine = engine
}
// ...
}
Then you can just mock the engine like this using JUnit as in your example:
@Mock
private Engine engine;
private Car car = new Car(engine);
@Test
public void drive() {
when(engine.isState()).thenReturn(true);
car.drive();
}
Or using Spock:
private Engine engine = Mock();
private Car car = new Car(engine);
def "test drive"() {
given:
engine.isState() >> true
expect:
car.drive();
}
来源:https://stackoverflow.com/questions/49305284/spock-mock-private-variable