Spock mock private variable
Asked Answered
D

2

7

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?

Dustindustman answered 15/3, 2018 at 17:3 Comment(3)
How is Engine set in the class you're testing?Wounded
@Wounded It's set in some private method which is called by init method.Dustindustman
You probably want to pass it in to the constructor, to make the class easier to testWounded
B
4

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
Bloodstained answered 16/3, 2018 at 2:27 Comment(0)
B
0

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();
}
Bluebill answered 25/7, 2018 at 6:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.