简体   繁体   中英

How to mock WebServiceContext injected into Web Service

I am struggling to Unit test the methods in my web service. All of the methods look at the injected WebServiceContext and pull a userId from that in order to make sure that the user is authorized. I have spent many hours trying to figure out how to mock up the WebServiceContext, but no matter what I try, the context is always null.

My end goal is to be able to return a userId that I specify in my test class so that I can proceed on to test the actual functionality of the rest of the method.

This is a stripped down version of how most of the methods are setup:

@HandlerChain(file = "/handler.xml")
@javax.jws.WebService (...)
public class SoapImpl
{
    @Resource
    private WebServiceContext context;

    public void methodUnderTest()
    {

        // context is NULL here - throws null pointer
        Principal userprincipal = context.getUserPrincipal();

        String userId = userprincipal.getName();


        // Do some stuff - I want to test this stuff, but can't get here
    }

}

This is how I am attempting to mock the context and test

@RunWith(MockitoJUnitRunner.class)
@PrepareForTest(SoapImpl.class)
public class SoapImplTest {

    @Mock
    WebServiceContext context;

    @Mock
    Principal userPrincipal;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testCreateOverrideRules() {

        SoapImpl testImpl = new SoapImpl();

        when(context.getUserPrincipal).thenReturn(userPrincipal);
        when(userPrincipal.getName()).thenReturn("testUser");

        testImpl.methodUnderTest();

        assertEquals(1,1);
    }

}

I know about dependency injection and passing the context in through the constructor, but I am not sure that I can do that here, because the context is injected through the @resource annotation. A constructor is never called. I don't fully understand how I would implement that.

Also, WebServiceContext and Principal are interfaces, so they cannot be instantiated, which makes this even more confusing. Can anyone help me out here? How can I mock the WebServiceContext and the Principal so I can get past this part of the method and move on to what I really want to test?

UPDATE I was able to solve the problem by using the @InjectMocks annotation as seen in the code below:

@RunWith(MockitoJUnitRunner.class)
@PrepareForTest(SoapImpl.class)
public class SoapImplTest {

    @InjectMocks
    private SoapImpl testImpl = new SoapImpl();

    @Mock
    WebServiceContext context;

    @Mock
    Principal userPrincipal;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testCreateOverrideRules() {

        when(context.getUserPrincipal).thenReturn(userPrincipal);
        when(userPrincipal.getName()).thenReturn("testUser");

        testImpl.methodUnderTest();

        assertEquals(1,1);
    }

}

1) You should have a constructor or setter that sets the context in your class under test. If you don't, you'll want to add one for this exact reason.

2) You don't need to instantiate WebServiceContext or Principal. Simply create mocks for them using Mockito.mock(WebServiceContext.class) and Mockito.mock(Principal.class). Then add Mockito.when(mockWebServiceContext).. to add behavior.

Keep in mind that if you're doing unit testing, you want to test only the logic in your method under test, and not any additional methods or integrations. This is why you want mock instances of both WebServiceContext and Principal. You do not want an integration test (presumably).

I was able to solve my problem by using the @InjectMocks annotation. This allowed me to inject my mocked objects into the class. The following two resources were helpful in figuring this out:

https://docs.oracle.com/javaee/6/tutorial/doc/bncjk.html

Injecting @Autowired private field during testing

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