How to mock an instance method on injected instance of the class under test?

258 Views Asked by At

I am trying to mock an instance method within a real object which is injected within my Test class in spock and I am using Micronaut (with Java) for writing my application. It is as follows:

class MyTestClass extends Specification {
    @Subject
    @Inject
    ClassUnderTest classUnderTest

    Event sampleEvent = getMockEvent();

    def "test1" () {
       given:
       def classUnderTestSpy = Spy(classUnderTest)

       when:
       def res = classUnderTestSpy.callTestMethod(sampleEvent)

       then:
       1 * classUnderTestSpy.isRunning(_ as Long) >> {
           return false
       }
       res != null
    }

    def getMockEvent() {
       new Event(/* Some attributes here */)
    }
}

The ClassUnderTest is something like this:

@Singleton
class ClassUnderTest {
    @Inject
    Class1 class1Instance;

    @Value("${com.myapplication.property}")
    Integer value;


    Object callTestMethod(Event event) {
       // Some code
       boolean isRunning = isRunning(event.id);
       // Rest of the code
    }

    public boolean isRunning(Long id) {
        return SomeOtherClass.staticMethod(id);
    }
}

Whenever the isRunning method is called the real SomeOtherClass.staticMethod() method call happens and the isRunning method returns true not false. Is there anyway I can Spy the injected ClassUnderTest instance and mock the instance method?

1

There are 1 best solutions below

5
ShingJo On

Again, cannot reproduce your issue.

Based on your example, I did the following and the test passes:

@MicronautTest //Your example is missing this, cannot even test without it
class SpyTest extends Specification{

    @Subject
    @Inject
    ClassUnderTest classUnderTest

    Event sampleEvent = getMockEvent();

    def "Spy Test"() {
        given:
        def classUnderTestSpy = Spy(classUnderTest)

        when:
        def results = classUnderTestSpy.callTestMethod(sampleEvent)

        then:
//        1 * classUnderTestSpy.isRunning(_ as Long) >> false //Preferred Groovy/Spock way
        1 * classUnderTestSpy.isRunning(_ as Long) >> {
            println("I am returning the correct thing!")
            false
        }
        results == "Is something running: false"
    }

    def getMockEvent() {
        new Event("Is something running: ")
    }
}
@Singleton
public class ClassUnderTest {
    private final InjectedClass iClass; //Noise in the example, not used

    public ClassUnderTest(InjectedClass iClass) { //Preferred way to inject
        this.iClass = iClass;
    }

    public String callTestMethod(Event event) {
        System.out.println("ClassUnderTest callTestMethod");
        boolean running = isRunning(0L);
        return event.message() + running;
    }

    public boolean isRunning(Long id) {
        System.out.println("ClassUnderTest isRunning with ID: " + id);
        return SomeOtherClass.staticMethod();
    }
}
@Singleton
public class InjectedClass {
    public String info() {
        return "I was injected";
    }
}

public record Event(String message) {}
@Singleton
public class SomeOtherClass {
    public static boolean staticMethod() {
        System.out.println("SomeOtherClass Static Method called");
        throw new RuntimeException("Should never get called");
    }
}