18

I have written a Restful Web service and have to test it using JUnit4. I have already written a Client using Jersey Client. But want to know if I can test my service only with junit4. Can someone help me with sample at least.

My rest service has authenticate method that takes user name, password and returns a token.

I have written test case for authenticate method. But I am not sure how to test using url.

public class TestAuthenticate {
    Service service  = new Service();
    String username = "user";
    String password = "password";
    String token;

    @Test(expected = Exception.class)
    public final void testAuthenticateInputs() {
        password = "pass";
        service.authenticate(username, password);
    }

    @Test(expected = Exception.class)
    public final void testAuthenticateException(){
        username = null;
        String token = service.authenticate(username, password);
        assertNotNull(token);
    }

    @Test
    public final void testAuthenticateResult() {
        String token = service.authenticate(username, password);
        assertNotNull(token);
    }
}
acm
  • 2,086
  • 3
  • 16
  • 34
Jenny
  • 345
  • 3
  • 5
  • 15
  • 1
    If you want to test using the URL, then you will need to start a server from your test. You can use an embedded server, which is pretty common for tests. Or you can make use of the Jersey Test Framework, which will start an embedded container for you. What Jersey version are you using? – Paul Samsotha Mar 31 '15 at 01:48
  • Check this [question][1] it explains how to mock your web service. [1]: http://stackoverflow.com/questions/31189159/mock-retrofit-service-with-mockito – Daniel Gomez Rico Jul 06 '15 at 17:52

3 Answers3

24

If you want to test using the URL, then you will need to start a server from your test. You can explicitly start an embedded server, which is pretty common for tests. Something like

public class MyResourceTest {

    public static final String BASE_URI = "http://localhost:8080/api/";
    private HttpServer server;

    @Before
    public void setUp() throws Exception {
        final ResourceConfig rc = new ResourceConfig(Service.class);
        server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);       
    }

    @After
    public void tearDown() throws Exception {
        server.stop();
    }

    @Test
    public void testService() {
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(BASE_URI).path("service");
        ...
    }
}

It's basically an integration test. You're starting the Grizzly container and loading a ResourceConfig to the server with only the Service class. Of course you could add more classes to the configuration. You can use "real" resource config if you wanted.

The above test uses this dependency

<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-grizzly2-http</artifactId>
    <version>${jersey2.version}</version>
</dependency>

Another option, which is the one I prefer, is to make use of the Jersey Test Framework, which will start an embedded container for you. A test might look something more like

public class SimpleTest extends JerseyTest {
 
    @Override
    protected Application configure() {
        return new ResourceConfig(Service.class);
    }
 
    @Test
    public void test() {
        String hello = target("service").request().get(String.class);
    }
}

Using this dependency

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>${jersey2.version}</version>
    <scope>test</scope>
</dependency>

And embedded Grizzly container will get started under the hood, with your ResourceConfig configuration. In both examples above it is assumed the @Path value for the Service class is service, as you can see in the test URLs.

Some Resources

Some Examples


UPDATE

If you're not using Maven, here are the jars you will need to run an embedded Grizzly container for the Jersey Test Fraemwork

enter image description here

I usually search for all my jars here. You can select the version and there should be a link in the next page, to download. You can use the search bar to search for the others.

Here's a simple running example, once you have all the jars

import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.spi.container.servlet.WebComponent;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.WebAppDescriptor;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import junit.framework.Assert;
import org.junit.Test;

public class SimpleTest extends JerseyTest {
    
    @Path("service")
    public static class Service {
        @GET
        public String getTest() { return "Hello World!"; }
    }

    public static class AppConfig extends DefaultResourceConfig {
        public AppConfig() {
            super(Service.class);
        }
    }
    
    @Override
    public WebAppDescriptor configure() {
        return new WebAppDescriptor.Builder()
                .initParam(WebComponent.RESOURCE_CONFIG_CLASS, 
                           AppConfig.class.getName())
                .build();
    }
    
    @Test
    public void doTest() {
        WebResource resource = resource().path("service");
        String result = resource.get(String.class);
        Assert.assertEquals("Hello World!", result);
        System.out.println(result);
    }
}

You're most likely not going to have the resources and ResourceConfig in the same class as the test, but I just want to keep it simple and all visible in one class.

Whether you are using a web.xml or a ResourceConfig subclass (as shown above), you can cut down what you test by using a separate ResourceConfig, built in the test class, as I have done. Otherwise, if you are using your normal ResourceConfig class, you can just replace it in the configure method.

The configure method, is pretty much just building a web.xml file, just in Java code. You can see different methods in the WebAppDescriptor.Builder, like initParam, which is the same as an <init-param> in your web xml. You can simply use the string in the arguments, but there are some constants, as I used above.

The @Test is you usual JUnit test that will run. It is using the Jersey Client. But instead of creating the Client, you can simply just use the preconfigured Client by just accessing the resource() method, which returns a WebResource. If you are familiar with the Jersey Client, then this class should not be new to you.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Thanks but this is pretty confusing. Can't I use only Junit and jmock and write test cases? Instead of using this Grizzly container? I am new to Jmock too. – Jenny Mar 31 '15 at 13:06
  • Can you explain what "test using url" means? I was under the assumption you want to make a request to the URL. You can't do that without a container running to that will host the Jersey application. Unless you mean something else. – Paul Samsotha Mar 31 '15 at 13:11
  • Yes. I have to make a request to ws. My ws is running in tomcat. – Jenny Mar 31 '15 at 13:14
  • So, Now I understand that to hit Rest web service, we have to use JerseyTest framework or Rest Assured framework along with Junit(not req) and we cannot do it alone with junit. Please correct me If I am wrong. – Jenny Mar 31 '15 at 15:08
  • The same way you are running your Jersey app on a Tomcat server, you can run the Jersey app from your tests by running it on an embedded server that started when your test starts and stops when it's done testing. That's what I have done in the first example, and that's what Jersey Test framework does for you under the hood. This is done over JUnit. Once all the tests are done, the server stops – Paul Samsotha Mar 31 '15 at 16:26
  • I can help you get started, but I need a little more information. Like what version of Jersey you are using, and if you are using Maven or not. My answer above, assumes you are using Maven. If not, I can help you find the jars you need to add to get it up and running. – Paul Samsotha Mar 31 '15 at 16:42
  • Thanks. I am using Jersey 1.19 and for now we are not using Maven.(We might use gradle though). Now my req is to use Jersey Test framework and Junit 4 and Jmock. (if that makes any sense). – Jenny Mar 31 '15 at 17:00
  • See my update. Let me know if you need help configuring it. If you need help and you are using a web.xml, then post your web.xml in your original post. If you are using a `ResourceConfig`, then I'm thinking configuration should be pretty straight forward, based on the example I provided. As far as JMock, I don't use it. You would only needed it if you wanted to mock some services, like data access objects, but like I said I don't use JMock. You can see an example I linked above, using Mockito, which mocks a DAO – Paul Samsotha Mar 31 '15 at 17:39
  • Thanks! Will work on this and let you know if I need any help. – Jenny Mar 31 '15 at 17:51
  • 1
    Excellent explanation, setup documentation for implementing and overall perfect answer to this question. Thank you for this. I didn't even know Jersey had a built in server container to call as a mock test config. This makes it easy to test simple service methods for test coverage. – Clint L Jul 12 '16 at 11:33
  • In the javadoc for `stop()`, it says to use [`shutdownNow()`](https://www.javadoc.io/doc/org.glassfish.grizzly/grizzly-http-server/2.3.28/org/glassfish/grizzly/http/server/HttpServer.html#shutdownNow()) instead. – Paul Samsotha Jan 06 '20 at 03:27
  • @PaulSamsotha I am getting `javax.ws.rs.ProcessingException: RESTEASY003145: Unable to find a MessageBodyReader of content-type application/json and type class java.lang.String` on `String hello = target("service").request().get(String.class);` any idea? – Jad Chahine Mar 05 '20 at 10:04
  • @JadChahine You must either be on JBoss/Wildfly or you have RESTEasy client on the classpath. You need to disable RESTEasy or remove it, respectively. – Paul Samsotha Mar 09 '20 at 13:15
  • @PaulSamsotha I finally solved my problem by registering to `ResteasyJacksonProvider` so I have now `Response response = target("path here") .register(ResteasyJacksonProvider.class) .request().get();` – Jad Chahine Mar 16 '20 at 12:31
0

Take a look at Alchemy rest client generator. This can generate a proxy implementation for your JAX-RS webservice class using jersey client behind the scene. Effectively you will call you webservice methods as simple java methods from your unit tests. Handles http authentication as well.

There is no code generation involved if you need to simply run tests so it is convenient.

The demo here setup up grizzly and uses the generator above to run junit tests.

Disclaimer: I am the author of this library.

0

I think @peeskillet has given you the needed prerequisites, i.e you need to run your web-service in an embedded web server. You could also look into dropwizard or spring-boot support for doing this conveniently.

As for actually verifying the response I would keep it simple and go with JUnit & http-matchers (see https://github.com/valid4j/http-matchers)

keyoxy
  • 4,423
  • 2
  • 21
  • 18