user3280180
user3280180

Reputation: 1403

Dropwizard Integrated Testing with TestResource

Does anyone knows how to add a test Resource (i.e. one that is only for testing purposes and not added in run() method of the app)?

Here is an example:

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

and

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

My problem is that the added resource is not added and I get resource not found 404 error response. It seems that I am registering the new resource after resource publishing and there is no refresh inside Dropwizard after start.

I dont want to extend my Application class and I dont want to insert test code into my real application code. Does anyone knows how to register the test resource without registering it in run() method of the Application?

This works, but a new class is needed:

public class TestService extends MyService{


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

}

Call in JUnit as already known:

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

Upvotes: 7

Views: 13858

Answers (4)

gli00001
gli00001

Reputation: 701

public class TestMain extends 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();
                        }
                    });
}

}

Upvotes: 0

dim42
dim42

Reputation: 1121

I had the similar issue with the @ClassRule, maybe it can help to somebody..
In my test (Groovy) the invocation of RULE.getApplication() or getEnvironment() from @BeforeClass method returned null:

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

shown

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

I.e. RULE.testSupport had both null application and environment.

I found out that the call to RULE.testSupport.before() just before run() solves the error:

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

And then @AfterClass method:

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

Or just use @Rule instead of @ClassRule and call

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

inside of @Before method instead of @BeforeClass.
Though It seems strange, maybe there is some other better solution exists..

Upvotes: 0

th3morg
th3morg

Reputation: 4789

Edit: Removing previous answer because it didn't solve your problem the way you wanted to do it.

I dug into the environment startup code and realized the reason why registering a controller didn't make it available is because jetty had already been started. If you stop jetty, register your controller and start jetty back up again, your resource will be available and you can use it in your test.

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

Upvotes: 5

Jan Galinski
Jan Galinski

Reputation: 12003

You can test the Resource itself in a Jersey Container without starting a full dw-instance.

Check the "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", "[email protected]");

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

Upvotes: 2

Related Questions