2

There is a Service class and a Util class with two static methods as shown.

public class Service {
    public String doSomething() {
        return "something";
    }
}

public final class Util {
    public static String utilFuncCallingService(Service service) {
        //some code
        System.out.println("Util class calling doSomething on service");
        return service.doSomething();
    }
    public static String utilFuncReturningString() {
        return "string";
    }
}

The main class (SUT) is,

public class MyClass {
    public final Service service;

    public MyClass(Service service) {
        this.service = service;
    }

    public void method() {
        System.out.println("Response: " + Util.utilFuncCallingService(service));
    }
}

It calls the Util.utilFuncCallingService method passing the Service instance.

The JUnit test is:

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
    @Mock
    private Service service;

    @Before
    public void setup() {
        when(Util.utilFuncCallingService(service))
                .thenReturn("mock-response");
    }

    @Test
    public void test() {
        MyClass myClass = new MyClass(service);

        myClass.method();
    }
}

Running this, it prints,

Util class calling doSomething on service
Util class calling doSomething on service
Response: mock-response

The first line was printed during setup of test and the second during actual test.

  1. How did the stub call when(Util.utilFuncCallingService(service)).thenReturn(..) become equivalent of writing when(service.doSomething()).thenReturn("mock-response") here?

Mockito wouldn't have allowed us to stub Util.utilFuncReturningString() since it is a static method. How did the stub call to Util.utilFuncCallingService() work here?

I've worked with JUnit quite a lot, but I feel I'm missing something very basic here.

Thiyagu
  • 17,362
  • 5
  • 42
  • 79

1 Answers1

1

There are a few parts of to the question.

First, Mockito does support mocking static methods.

@ExtendWith(MockitoExtension.class)
public class MyClassTest {
    @Mock
    private Service service;

    @Test
    public void test() {
        try(MockedStatic<Util> dummyStatic = Mockito.mockStatic(Util.class)) {
            dummyStatic.when(() -> Util.utilFuncCallingService(service)).thenReturn("mock-response");
            MyClass myClass = new MyClass(service);
            myClass.method();
        }
    }
}

// Prints: Response: mock-response

Second, what went wrong with your test and why Mockito did not complain?

You need to know that Mockito stubbing is a stack-based machine - if you call a method on a mock inside when invoking Mockito.when, this call is registered on a stack, thus mockito knows which method to stub.

In your test, you called Util.utilFuncCallingService(service) which got executed, which in turn called service.doSomething() - this is a method call on a mock, so it landed on the stack. There were no other method calls on mocks, so the suubbed method is service.doSomething()

Observe:

@ExtendWith(MockitoExtension.class)
public class MyClassTest {
    @Mock
    private Service service;

    @Test
    public void test() {
        when(Util.utilFuncCallingService(service)).thenReturn("mock-response");
        System.out.println(service.doSomething());
    }
}

// Prints:
// Util class calling doSomething on service
// mock-response

You may take a look at:

Lesiak
  • 22,088
  • 2
  • 41
  • 65
  • I didn't know this is how Mockito worked (like registering calls on stacks). Couldn't find proper documentation related to this at https://site.mockito.org/ – Thiyagu Sep 08 '22 at 07:41
  • @user7 I added a few references in my answer – Lesiak Sep 08 '22 at 08:00