使用 JerseyTest、Maven 和 TestNG 测试 Jersey-Spring 集成

发布于 2024-10-02 12:33:02 字数 1644 浏览 0 评论 0原文

我想使用 Jersey 测试框架测试我的 Jersey 资源。

我按照此处提供的描述

创建一个简单的示例。我的示例作为 git 存储库托管在 http://github.com/rmetzler/Jersey-Test 上。

$ mvn jetty:run 按预期工作,但在运行 $ mvn clean test 时我不断收到 NullPointerExceptions。

java.lang.NullPointerException
at com.sun.jersey.spi.container.ContainerResponse.mapException(ContainerResponse.java:429)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1295)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1239)
at com.sun.jersey.test.framework.impl.container.inmemory.TestResourceClientHandler.handle(TestResourceClientHandler.java:119)
at com.sun.jersey.api.client.Client.handle(Client.java:616)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:559)
at com.sun.jersey.api.client.WebResource.get(WebResource.java:182)
at example.jersey.spring.MyResourceTest.testMyResource(MyResourceTest.java:30)
...

我敢打赌我犯了一个我无法发现的小错误。我会向另一位开发人员展示我的源代码,但不幸的是我独自在家工作。那么也许你们中有人可以帮助我?

更新

我通过运行 $ mvn eclipse:eclipse 创建了一个 Eclipse 项目。现在,当我在 Eclipse 中作为 JUnit Test 运行测试时,它是绿色的。当将其作为 TestNG Test 运行时,它会失败。所以我猜这与 TestNG 执行测试的方式有关。

I want to test my Jersey resources with the Jersey Test-Framework.

I followed the descriptions provided here

to create a simple example. My example is hosted as git repository on http://github.com/rmetzler/Jersey-Test .

$ mvn jetty:run works as expected but I keep getting NullPointerExceptions when running $ mvn clean test.

java.lang.NullPointerException
at com.sun.jersey.spi.container.ContainerResponse.mapException(ContainerResponse.java:429)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1295)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1239)
at com.sun.jersey.test.framework.impl.container.inmemory.TestResourceClientHandler.handle(TestResourceClientHandler.java:119)
at com.sun.jersey.api.client.Client.handle(Client.java:616)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:559)
at com.sun.jersey.api.client.WebResource.get(WebResource.java:182)
at example.jersey.spring.MyResourceTest.testMyResource(MyResourceTest.java:30)
...

I bet I made a small mistake that I'm unable to find. I would show my source to another developer but unfortunately I work alone at home. So maybe someone of you could help me?

UPDATE

I created an Eclipse project by running $ mvn eclipse:eclipse . Now when I run the test as JUnit Test in Eclipse it is green. When running it as TestNG Test it fails. So I guess it has something to do with how the test is executed by TestNG.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦里的微风 2024-10-09 12:33:02

我做了同样的事情,除了我使用的是 guice,而不是 spring。这是我的实现(抱歉,没有时间清理,您必须自己提取有趣的部分)。请注意,我使用了委托 jerseytest 类,因此我可以从基本测试类继承一些代码。此外,您还必须将 junit 前置方法和后置方法映射到 testng 方法。

希望这会有所帮助。


package mypackage;

import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.URL;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.commons.lang.UnhandledException;
import org.apache.xerces.dom.DOMInputImpl;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.FunctionObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.w3c.dom.Document;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.reflect.core.Reflection.staticMethod;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
import com.sun.jersey.spi.container.WebApplication;
import com.sun.jersey.spi.container.WebApplicationFactory;
import com.sun.jersey.test.framework.AppDescriptor;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.LowLevelAppDescriptor;
import com.sun.jersey.test.framework.impl.container.inmemory.TestResourceClientHandler;
import com.sun.jersey.test.framework.spi.container.TestContainer;
import com.sun.jersey.test.framework.spi.container.TestContainerException;
import com.sun.jersey.test.framework.spi.container.TestContainerFactory;
import com.sun.jersey.test.framework.spi.container.inmemory.InMemoryTestContainerFactory;

import mypackage.StaticConfig;
import mypackage.MediaTypes;

public abstract class JerseyIntegrationTestBase extends TransactionalIntegrationTestBase {

    private static final Logger LOG = LoggerFactory.getLogger( JerseyIntegrationTestBase.class );

    private static final class GuiceInMemoryTestContainerFactory extends InMemoryTestContainerFactory {

        @Override
        public TestContainer create( final URI baseUri, final AppDescriptor ad ) {
            return new GuiceInMemoryTestContainer( baseUri, (LowLevelAppDescriptor) ad );
        }

        /**
         * Kopie der Klasse im inmemory-Testcontainer von Jersey, leicht an Guice-Injection angepasst. The class defines methods for
         * starting/stopping an in-memory test container, and for running tests on the container.
         */
        private static class GuiceInMemoryTestContainer implements TestContainer {

            final URI baseUri;

            final ResourceConfig resourceConfig;

            final WebApplication webApp;

            /**
             * Creates an instance of {@link GuiceInMemoryTestContainer}
             * 
             * @param Base
             *            URI of the application
             * @param An
             *            instance of {@link LowLevelAppDescriptor}
             */
            private GuiceInMemoryTestContainer( final URI baseUri, final LowLevelAppDescriptor ad ) {
                this.baseUri = UriBuilder.fromUri( baseUri ).build();

                LOG.info( "Creating low level InMemory test container configured at the base URI " + this.baseUri );

                resourceConfig = ad.getResourceConfig();
                // Falls man mal in Tests die requests und responses sehen möchte:
                // this.resourceConfig.getProperties().put( ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS,
                // LoggingFilter.class.getName() );
                // this.resourceConfig.getProperties().put( ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS,
                // LoggingFilter.class.getName() );
                resourceConfig.getProperties().putAll( StaticConfig.getJerseyParams() );
                webApp = WebApplicationFactory.createWebApplication();
            }

            @Override
            public Client getClient() {
                ClientConfig clientConfig = null;
                final Set providerSingletons = resourceConfig.getProviderSingletons();

                if ( providerSingletons.size() > 0 ) {
                    clientConfig = new DefaultClientConfig();
                    for ( final Object providerSingleton : providerSingletons ) {
                        clientConfig.getSingletons().add( providerSingleton );
                    }
                }

                final Client client = clientConfig == null
                    ? new Client( new TestResourceClientHandler( baseUri, webApp ) )
                    : new Client( new TestResourceClientHandler( baseUri, webApp ), clientConfig );

                return client;
            }

            @Override
            public URI getBaseUri() {
                return baseUri;
            }

            @Override
            public void start() {
                if ( !webApp.isInitiated() ) {
                    LOG.info( "Starting low level InMemory test container" );
                    webApp.initiate( resourceConfig, new GuiceContainer( null ).new ServletGuiceComponentProviderFactory(
                            resourceConfig, IntegrationTestBase.getInjector() ) );
                }
            }

            @Override
            public void stop() {
                if ( webApp.isInitiated() ) {
                    LOG.info( "Stopping low level InMemory test container" );
                    webApp.destroy();
                }
            }

        }
    }

    private final JerseyTest _jerseyTest;

    public JerseyIntegrationTestBase() {

        // PackagesResourceConfig.getPackages macht genau das, was wir wollen, ist aber private, daher
        // auf die harte Tour...
        // FORMATTER: OFF
        final String[] packages =
                staticMethod( "getPackages" ).withReturnType( String[].class ).withParameterTypes( Map.class )
                    .in( PackagesResourceConfig.class ).invoke( StaticConfig.getJerseyParams() );
        // FORMATTER: ON
        _jerseyTest = new JerseyTest( new LowLevelAppDescriptor.Builder( packages ).build() ) {
            @Override
            protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
                return new GuiceInMemoryTestContainerFactory();
            }
        };
    }

    /**
     * @return
     * @see JerseyTest#client().
     */
    protected Client client() {
        return _jerseyTest.client();
    }

    @BeforeClass( alwaysRun = true )
    public void setUp() throws Exception {
        _jerseyTest.setUp();
    }

    @AfterClass( alwaysRun = true )
    public void tearDown() throws Exception {
        _jerseyTest.tearDown();
    }
}

I did the same thing except for I am using guice, not spring. This is my implementation (sorry, no time to clean up, you'll have to extract the interesting parts yourself). Note that I used a delegate jerseytest class so I can inherit some code from my base test class. Also you have to map the junit pre- and post-methods to testng ones.

Hope this helps a bit.


package mypackage;

import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.URL;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.commons.lang.UnhandledException;
import org.apache.xerces.dom.DOMInputImpl;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.FunctionObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.w3c.dom.Document;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.reflect.core.Reflection.staticMethod;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
import com.sun.jersey.spi.container.WebApplication;
import com.sun.jersey.spi.container.WebApplicationFactory;
import com.sun.jersey.test.framework.AppDescriptor;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.LowLevelAppDescriptor;
import com.sun.jersey.test.framework.impl.container.inmemory.TestResourceClientHandler;
import com.sun.jersey.test.framework.spi.container.TestContainer;
import com.sun.jersey.test.framework.spi.container.TestContainerException;
import com.sun.jersey.test.framework.spi.container.TestContainerFactory;
import com.sun.jersey.test.framework.spi.container.inmemory.InMemoryTestContainerFactory;

import mypackage.StaticConfig;
import mypackage.MediaTypes;

public abstract class JerseyIntegrationTestBase extends TransactionalIntegrationTestBase {

    private static final Logger LOG = LoggerFactory.getLogger( JerseyIntegrationTestBase.class );

    private static final class GuiceInMemoryTestContainerFactory extends InMemoryTestContainerFactory {

        @Override
        public TestContainer create( final URI baseUri, final AppDescriptor ad ) {
            return new GuiceInMemoryTestContainer( baseUri, (LowLevelAppDescriptor) ad );
        }

        /**
         * Kopie der Klasse im inmemory-Testcontainer von Jersey, leicht an Guice-Injection angepasst. The class defines methods for
         * starting/stopping an in-memory test container, and for running tests on the container.
         */
        private static class GuiceInMemoryTestContainer implements TestContainer {

            final URI baseUri;

            final ResourceConfig resourceConfig;

            final WebApplication webApp;

            /**
             * Creates an instance of {@link GuiceInMemoryTestContainer}
             * 
             * @param Base
             *            URI of the application
             * @param An
             *            instance of {@link LowLevelAppDescriptor}
             */
            private GuiceInMemoryTestContainer( final URI baseUri, final LowLevelAppDescriptor ad ) {
                this.baseUri = UriBuilder.fromUri( baseUri ).build();

                LOG.info( "Creating low level InMemory test container configured at the base URI " + this.baseUri );

                resourceConfig = ad.getResourceConfig();
                // Falls man mal in Tests die requests und responses sehen möchte:
                // this.resourceConfig.getProperties().put( ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS,
                // LoggingFilter.class.getName() );
                // this.resourceConfig.getProperties().put( ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS,
                // LoggingFilter.class.getName() );
                resourceConfig.getProperties().putAll( StaticConfig.getJerseyParams() );
                webApp = WebApplicationFactory.createWebApplication();
            }

            @Override
            public Client getClient() {
                ClientConfig clientConfig = null;
                final Set providerSingletons = resourceConfig.getProviderSingletons();

                if ( providerSingletons.size() > 0 ) {
                    clientConfig = new DefaultClientConfig();
                    for ( final Object providerSingleton : providerSingletons ) {
                        clientConfig.getSingletons().add( providerSingleton );
                    }
                }

                final Client client = clientConfig == null
                    ? new Client( new TestResourceClientHandler( baseUri, webApp ) )
                    : new Client( new TestResourceClientHandler( baseUri, webApp ), clientConfig );

                return client;
            }

            @Override
            public URI getBaseUri() {
                return baseUri;
            }

            @Override
            public void start() {
                if ( !webApp.isInitiated() ) {
                    LOG.info( "Starting low level InMemory test container" );
                    webApp.initiate( resourceConfig, new GuiceContainer( null ).new ServletGuiceComponentProviderFactory(
                            resourceConfig, IntegrationTestBase.getInjector() ) );
                }
            }

            @Override
            public void stop() {
                if ( webApp.isInitiated() ) {
                    LOG.info( "Stopping low level InMemory test container" );
                    webApp.destroy();
                }
            }

        }
    }

    private final JerseyTest _jerseyTest;

    public JerseyIntegrationTestBase() {

        // PackagesResourceConfig.getPackages macht genau das, was wir wollen, ist aber private, daher
        // auf die harte Tour...
        // FORMATTER: OFF
        final String[] packages =
                staticMethod( "getPackages" ).withReturnType( String[].class ).withParameterTypes( Map.class )
                    .in( PackagesResourceConfig.class ).invoke( StaticConfig.getJerseyParams() );
        // FORMATTER: ON
        _jerseyTest = new JerseyTest( new LowLevelAppDescriptor.Builder( packages ).build() ) {
            @Override
            protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
                return new GuiceInMemoryTestContainerFactory();
            }
        };
    }

    /**
     * @return
     * @see JerseyTest#client().
     */
    protected Client client() {
        return _jerseyTest.client();
    }

    @BeforeClass( alwaysRun = true )
    public void setUp() throws Exception {
        _jerseyTest.setUp();
    }

    @AfterClass( alwaysRun = true )
    public void tearDown() throws Exception {
        _jerseyTest.tearDown();
    }
}
枯叶蝶 2024-10-09 12:33:02

因为 JerseyTest 使用 Junit 的 @Before 注释来初始化应用程序,所以您必须扩展 JerseyTest 才能启用 testng 支持,如下所示:

public class JerseyTestNG extends JerseyTest { 
    @Override
    protected Application configure() {
        ResourceConfig config = new ResourceConfig(YourService.class);
    }

    @BeforeClass 
    public void setUp() {
        super.setUp();
    }

    @AfterClass
    public void tearDown() {
        super.tearDown();
    }
}

@BeforeClass 还将确保在使用 Surefire 插件时,Jersey 容器准备就绪后执行其中的所有测试。否则这些测试很快就会失败。

如果您想读取 applicationContext-test.xml 而不是默认的,请为 ResourceConfig 设置一个属性:

config.setProperties(new HashMap<String, String>() {{
    put("contextConfigLocation", "applicationContext-test.xml");
}});

另外,向 ClientConfig 添加一些功能可能会有所帮助:

@Override
protected void configureClient(ClientConfig config) {
    config.register(LoggingFilter.class);
    config.register(MOXyJsonProvider.class);
    config.register(new EncodingFeature(GZipEncoder.class));
}

全部在 Jersey 2.6 上进行了测试。

Because JerseyTest is using @Before annotation from Junit for initialising the application, and you have to extend JerseyTest to enable testng support, like this:

public class JerseyTestNG extends JerseyTest { 
    @Override
    protected Application configure() {
        ResourceConfig config = new ResourceConfig(YourService.class);
    }

    @BeforeClass 
    public void setUp() {
        super.setUp();
    }

    @AfterClass
    public void tearDown() {
        super.tearDown();
    }
}

@BeforeClass also will make sure all tests within are executed after the Jersey container is ready when using surefire plugin. Otherwise those tests will fail quickly.

and if you want to it read applicationContext-test.xml other than the default one, set one more property to ResourceConfig:

config.setProperties(new HashMap<String, String>() {{
    put("contextConfigLocation", "applicationContext-test.xml");
}});

also, adding some features to ClientConfig maybe helpful:

@Override
protected void configureClient(ClientConfig config) {
    config.register(LoggingFilter.class);
    config.register(MOXyJsonProvider.class);
    config.register(new EncodingFeature(GZipEncoder.class));
}

All tested on Jersey 2.6.

笑脸一如从前 2024-10-09 12:33:02

此处使用 Jersey + Spring + TestNG + Jetty 的简单示例:

http://ameethpaatil.blogspot.com/2011/09/restful-webservice-jersey-spring-30x.html

A simple example using Jersey + Spring + TestNG + Jetty here:

http://ameethpaatil.blogspot.com/2011/09/restful-webservice-jersey-spring-30x.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文