使用TestResource进行Dropwizard集成测试

时间:2014-10-15 11:15:07

标签: java rest testing dropwizard

是否有人知道如何添加测试资源(即仅用于测试目的且未在应用程序的run()方法中添加的测试资源)?

以下是一个例子:

public class MyTest {   
    @ClassRule
    public static final DropwizardAppRule<TestConfiguration> RULE =
            new DropwizardAppRule<TestConfiguration>(MyApp.class, "my-app-config.yaml");


    @BeforeClass
    public static void setUpBeforeClass() throws Exception
    {
        MyTest.RULE.getEnvironment().jersey().register(new JustForTestingResource());
    }


    @Test
    public final void testTestResource()
    {
        Client client = new Client();

        ClientResponse response = client.resource(
            String.format("http://localhost:%d/rest/v1/test", RULE.getLocalPort()))
            .get(ClientResponse.class);

        assertThat(response.getStatus(), is(200));   
    }
}

public class JustForTestingRessource {


    @GET
    @Path("test")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getInTestResource()
    {
        return Response.status(Status.OK).type(MediaType.TEXT_PLAIN).entity("get @Path(\"test\") is ok").build();
    }
}

我的问题是添加的资​​源没有添加,我找不到资源404错误响应。似乎我在资源发布后注册了新资源,并且启动后Dropwizard中没有刷新。

我不想扩展我的Application类,我不想将测试代码插入到我的实际应用程序代码中。有没有人知道如何注册测试资源而不在Application?的run()方法中注册它?

这样可行,但需要一个新类:

public class TestService extends MyService{


    @Override
    public void run(
        TestConfigurationconfiguration,
        Environment environment) throws ClassNotFoundException
    {       
        environment.jersey().register(new JustForTestingRessource());
        super.run(configuration,environment);
    }

}

在JUnit中调用已知:

@ClassRule
public static DropwizardAppRule<TestConfiguration> RULE =
        new DropwizardAppRule<TestConfiguration>(TestService.class, "my-app-config.yaml");

4 个答案:

答案 0 :(得分:5)

编辑:删除以前的答案,因为它没有按您想要的方式解决问题。

我挖掘了环境启动代码并意识到注册控制器没有使其可用的原因是因为jetty已经启动了。如果您停止码头,请注册您的控制器并重新启动码头,您的资源将可用,您可以在测试中使用它。

@BeforeClass
public static void setUpBeforeClass() throws Exception
{
    MyTest.RULE.environment.applicationContext.stop()
    MyTest.RULE.environment.jersey().register(new JustForTestingResource())
    MyTest.RULE.environment.applicationContext.start()
}

答案 1 :(得分:2)

您可以在Jersey容器中测试资源本身,而无需启动完整的dw-instance。

检查"Testing Resources" section

import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.*;

public class PersonResourceTest {

     private static final PeopleStore dao = mock(PeopleStore.class);

     @ClassRule
     public static final ResourceTestRule resources = ResourceTestRule.builder()
        .addResource(new PersonResource(dao))
        .build();

     private final Person person = new Person("blah", "blah@example.com");

     @Before
     public void setup() {
         when(dao.fetchPerson(eq("blah"))).thenReturn(person);
         // we have to reset the mock after each test because of the
         // @ClassRule, or use a @Rule as mentioned below.
         reset(dao);
     }

     @Test
     public void testGetPerson() {
         assertThat(resources.client().resource("/person/blah").get(Person.class))
            .isEqualTo(person);
         verify(dao).fetchPerson("blah");
     }
 }

答案 2 :(得分:0)

我和@ClassRule有类似的问题,也许它对某人有帮助。
在我的测试(Groovy)中,从@BeforeClass方法调用RULE.getApplication()或getEnvironment()返回null:

def setupSpec() {
    RULE.application.run()
}

java.lang.NullPointerException: Cannot invoke method run() on null object

即。 RULE.testSupport同时具有null应用程序和环境。

我发现了这个电话 RULE.testSupport.before() 就在run()之前解决了错误:

def setupSpec() {
    RULE.testSupport.before()
    RULE.application.run()
}

然后是@AfterClass方法:

def cleanupSpec() {
    RULE.testSupport.after()
}

或者只使用@Rule而不是@ClassRule并调用

def setup() {
    RULE.application.run()
}

在@Before方法内部而不是@BeforeClass 虽然看起来很奇怪,但也许还有其他更好的解决方案。

答案 3 :(得分:0)

公共类TestMain扩展Main {

public static void main(String ... args) throws Exception {
    new TestMain().run(args);
}


@Override
public void initialize(Bootstrap<AppConfiguration> bootstrap) {
    super.initialize(bootstrap);
    bootstrap.addBundle(
                    new MigrationsBundle<AppConfiguration>() {
                        @Override
                        public DataSourceFactory getDataSourceFactory(
                                        AppConfiguration configuration) {
                            return configuration.getDataSourceFactory();
                        }
                    });
}

}