简体   繁体   中英

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.

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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM