Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow in-memory unit testing of resources using views? #513

Closed
chids opened this issue Mar 26, 2014 · 3 comments · Fixed by #966
Closed

Allow in-memory unit testing of resources using views? #513

chids opened this issue Mar 26, 2014 · 3 comments · Fixed by #966

Comments

@chids
Copy link
Contributor

chids commented Mar 26, 2014

Since ViewMessageBodyWriter contains @Context private HttpHeaders headers; it's not possible to unit test resources using views with the lightweight in-memory Jersey provider (using ResourceTestRule).

However since a MessageBodyWriter.writeTo receives the request headers as a MultivaluedMap<String, Object> argument there shouldn't be an absolute need for injecting HttpHeaders.

I did a very rough PoC by rewriting ViewMessageBodyWriter.detectLocale() into this horrid mess:

    private static Locale detectLocale(MultivaluedMap<String, Object> headers) {
        InBoundHeaders h = new InBoundHeaders();
        List<Object> accepts = headers.get(ACCEPT_LANGUAGE);
        if(accepts != null && accepts.size() > 0) {
            h.put(ACCEPT_LANGUAGE, Lists.transform(accepts, Functions.toStringFunction()));
        }
        ContainerRequest cr = new ContainerRequest(new WebApplicationImpl(), null, null, null, h, null);
        for (AcceptableLanguageTag langTag : HttpHelper.getAcceptLanguage(cr)) {
            Locale x = langTag.getAsLocale();
            if (!x.toString().contains("*")) { // Freemarker doesn't do wildcards well
                return x;
            }
        }
        return Locale.getDefault();
    }

I'd be happy to put some more effort into it and submit a PR if others think its valuable.

@robomark
Copy link

Yes, this would be helpful - I ended up running my tests with a similarly hacked copy of ViewMessageBodyWriter, which isn't a sustainable practice. Thanks for identifying this.

@petergphillips
Copy link

In fact HttpHeaders can be injected into the ViewMessageBodyWriter, in a similar fashion to #651. Using the ContextInjectableProvider from #651 the rule declaration becomes:

 @ClassRule
  public static final ResourceTestRule resources = ResourceTestRule.builder()
    .addResource(new MemberNodeResource(backend, mockNode()))
    .addProvider(new ViewMessageBodyWriter(new MetricRegistry()))
    .addProvider(new ContextInjectableProvider<HttpHeaders>(HttpHeaders.class))
    .build();

Note that I haven't setup a view renderer, so I will just get the plain html returned. Then to test:

        String response = resources.client().resource("/test/cancel").get(String.class);
        org.assertj.core.api.Assertions.assertThat(response).contains("Test Cancelled");

@carlo-rtr
Copy link
Member

If this #966 gets merged, then it should work. I verified.

package com.example.helloworld.resources;
import com.codahale.metrics.MetricRegistry;
import com.google.common.collect.Lists;
import io.dropwizard.testing.junit.ResourceTestRule;
import io.dropwizard.views.ViewMessageBodyWriter;
import io.dropwizard.views.ViewRenderer;
import io.dropwizard.views.mustache.MustacheViewRenderer;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.junit.ClassRule;
import org.junit.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;

public class ViewResourceTest {
    private static List<ViewRenderer> renders = Lists.<ViewRenderer>newArrayList(new MustacheViewRenderer());

    @ClassRule
    public static final ResourceTestRule resources = ResourceTestRule.builder()
            .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
            .addProvider(ViewResource.class)
            .addProvider(new ViewMessageBodyWriter(new MetricRegistry(), renders))
            .build();


    @Test
    public void testMustacheUTF8() {
        String view = resources.getJerseyTest().target("/views/utf8.mustache")
                .request().accept("text/html;charset=UTF-8").get(String.class);
        assertThat(view).isEqualTo("<html>\n" +
                "<body>\n" +
                "\n" +
                "<h1>This is an example of a view containing UTF-8 characters</h1>\n" +
                "\n" +
                "€€€€€€€€€€€€€€€€€€\n" +
                "\n" +
                "</body>\n" +
                "</html>");
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants