Julian
Julian

Reputation: 4055

jMockit - How make constructor invocation to return a mock

We are currently using Mockito + PowerMock as our main mocking framework and had a few issues with this once started moving some of our code to java 8. Because of this we decided to evaluate jMockit as an alternative. I have quite a good understanding of mocking concepts but I admit that my experience with jMockit is very limited.

However I am having problems with testing something that in my view should be very basic: the class under test creates an instance of some other class inside its constructor using new. That new invocation is the thing that I would like to make return a mock instance.

Here is the code like the one I am using: package com.some.org.some.app;

import mockit.Expectations;
import mockit.Injectable;
import mockit.Mocked;
import org.testng.annotations.Test;

public class ClassUnderTestTest {
    interface SomeService {
        void doWork();
    }

    class ClassUnderTest {
        private final SomeService service;

        public ClassUnderTest() {
            this.service = new SomeService() {
                @Override
                public void doWork() {
                }
            };
        }
    }

    @Injectable
    private SomeService mockService;

    @Test
    public void shouldBeAbleToMaskVariousNumbers() throws Exception {
        new Expectations() {{
            new ClassUnderTest();
            result = mockService;
        }};
    }
}

When running the above I am getting the exception below:

java.lang.IllegalStateException: Missing invocation to mocked type at this point;
please make sure such invocations appear only after the declaration of a suitable
mock field or parameter

I am using TestNG as a testing framework and in reality my test method has a bunch of parameters as it is expecting some test data being passed by a data provider.

This is pretty basic and it looks like my approach is not the jMockit way. Thank you in advance for your support.

Upvotes: 1

Views: 3578

Answers (1)

Rogério
Rogério

Reputation: 16380

This is very easy to do with JMockit:

public class ClassUnderTestTest {
    interface SomeService { int doWork(); }

    class ClassUnderTest {
        private final SomeService service;

        ClassUnderTest() {
            service = new SomeService() {
                @Override public int doWork() { return -1; }
            };
        }

        int useTheService() { return service.doWork(); }
    }

    // This annotation is a variation on @Mocked, which extends
    // mocking to any implementation classes or subclasses of
    // the mocked base type.
    @Capturing SomeService mockService;

    @Test
    public void shouldBeAbleToMaskVariousNumbers() {
        new Expectations() {{ mockService.doWork(); result = 123; }};

        int n = new ClassUnderTest().useTheService();

        assertEquals(123, n);
    }
}

Upvotes: 3

Related Questions