Test @Webservice EJBs with WebServiceContext (usin

2019-02-15 14:26发布

问题:

I have some EJBs as JAX-WS Web Service:

@WebService
@Stateless
@Remote(MobileFacade.class)
public class MobileFacadeBean implements MobileFacade {
    ... 

   @Resource
   WebServiceContext wsc;

    ...
}

Within this Web Service class, a WebServiceContext is injected via @Resource. I use this WebServiceContext to get the principal in the implementation. This works quite well, but now I wonder how to (Unit-)test this class!

So far, I was using OpenEJB to test my EJBs. Since the Web Service class also is an Stateless Session Bean, I would really like to use the same approach here. However, it does not work that easy - of course, it complains that there is no WebServiceContext when not called as a Web Service.

So the first question is: are there any ways to mock the WebServiceContext in OpenEJB?

And if no, what approach would you favour to test this kind of Web Service classes?

Cheers, Frank

回答1:

There are a handful of @WebService unit test examples in the OpenEJB examples zip file. Everything you want should work fine.

  • simple-webservice
  • webservice-attachments
  • webservice-security
  • webservice-ws-security

The webservice-security example sounds exactly like what you want. The version online uses @RolesAllowed to make the container do the security check rather than doing it in code, but it is possible to check the principle in code. Here's a slightly modified version of that example that worked for me with no issues.

The bean

@DeclareRoles(value = {"Administrator"})
@Stateless
@WebService(
        portName = "CalculatorPort",
        serviceName = "CalculatorWsService",
        targetNamespace = "http://superbiz.org/wsdl",
        endpointInterface = "org.superbiz.calculator.CalculatorWs")
public class CalculatorImpl implements CalculatorWs, CalculatorRemote {

    @Resource
    private WebServiceContext webServiceContext;

    @RolesAllowed(value = {"Administrator"})
    public int sum(int add1, int add2) {
        // maybe log the principal or something -- prints "jane" in the test
        System.out.print(webServiceContext.getUserPrincipal());
        return add1 + add2;
    }

    @RolesAllowed(value = {"Administrator"})
    public int multiply(int mul1, int mul2) {
        return mul1 * mul2;
    }
}

The Test

public class CalculatorTest extends TestCase {

    private InitialContext initialContext;

    protected void setUp() throws Exception {
        Properties properties = new Properties();
        properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
        properties.setProperty("openejb.embedded.remotable", "true");

        initialContext = new InitialContext(properties);
    }

    /**
     * Create a webservice client using wsdl url
     *
     * @throws Exception
     */
    public void testCalculatorViaWsInterface() throws Exception {
        URL url = new URL("http://127.0.0.1:4204/CalculatorImpl?wsdl");
        QName calcServiceQName = new QName("http://superbiz.org/wsdl", "CalculatorWsService");
        Service calcService = Service.create(url, calcServiceQName);
        assertNotNull(calcService);

        CalculatorWs calc = calcService.getPort(CalculatorWs.class);
        ((BindingProvider) calc).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "jane");
        ((BindingProvider) calc).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "waterfall");
        assertEquals(10, calc.sum(4, 6));
        assertEquals(12, calc.multiply(3, 4));
    }
}

Libraries

If using maven, switch your normal openejb-core dependency to openejb-cxf like so. This will add Apache CXF and the OpenEJB/CXF integration code to your classpath.

<dependency>
  <groupId>org.apache.openejb</groupId>
  <artifactId>openejb-cxf</artifactId>
  <version>3.1.4</version>
  <scope>test</scope>
</dependency>

If not using maven, simplest approach is to just add all the jars from the lib/ directory of the OpenEJB zip file.



回答2:

David,In your answer in CalculatorTest you have used CalculatorWs.class, Is it same interface as it is used in webservice side implementation. Do we have to create web service client?

Also in David's example Instead of


QName calcServiceQName = new QName("http://superbiz.org/wsdl", "CalculatorWsService");

use


QName calcServiceQName = new QName("http://superbiz.org/wsdl", "CalculatorPort");