Spock mock private variable

烈酒焚心 提交于 2021-01-03 09:54:22

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!