All posts by Sascha Eissler

Testing REST-clients with “Jersey Test Framework” in specs2

In a “Microservice Architecture” there will likely be the case, that one service depends on another one. So you normally implement some kind of client in the service that connects to the other service. When writing unit tests you can then mock this client and make it behave like you expect. But how do you test the client itself? Therefore you need to mock the other service and make it response as you expect.

For writing tests against a jersey-server there exists the “Jersey Test Framework”. Here you use the jersey application as the system under test (SUT). But you can easiliy use this framework to use the application as a mocked service and run tests against the client using this mocked service.

We are mainly writing our code in scala and therefore writing our tests in specs2. Thats the reaseon why I wanted to find a way how I can use JerseyTest easiliy in my specs tests. Inspired by the project specs2-embedmongo I created a FragmentsBuilder that injects an embedded JerseyService into a spec.

trait EmbedService extends FragmentsBuilder {
  self: SpecificationLike =>

  //Override to configure the application
  def configure(): Application

  // Create a JAX-RS web target whose URI refers to the Jersey application
  def target(): WebTarget = {
    client.target(tc.getBaseUri)
  }

  private lazy val tc = {
    val baseUri = UriBuilder.fromUri("http://localhost/").port(8080).build()
    val context = DeploymentContext.builder(configure()).build
    val tcf = new GrizzlyTestContainerFactory
    tcf.create(baseUri, context)
  }

  private lazy val client = {
    ClientBuilder.newClient()
  }

  override def map(fs: => Fragments) = startService ^ fs ^ stopService

  private def startService() = {
    Step({ tc.start() })
  }

  private def stopService() = {
    Step({ tc.stop() })
  }

}

To use it you only have to mix in this trait and configure your expected behavior as a jersey application.

class EmbedServiceSpec extends Specification with EmbedService {

  override def configure(): Application = {
    new ResourceConfig(classOf[HelloResource])
  }

  "Embed service" should {
    "be able to return 'Hello World!' on a GET request" in {
      val hello = target().path("hello").request().get(classOf[String])
      hello must be equalTo("Hello World!")
    }
  }

}

@Path("hello")
class HelloResource {
  @GET
  def getHello() = "Hello World!"
}

The last thing you have to do is to inject the WebTarget into the Client you want to test.

class HelloResourceClientSpec extends Specification with EmbedService {

  override def configure(): Application = {
    new ResourceConfig(classOf[HelloResource])
  }

  val sut = new HelloResourceClient(target())

  "HelloResourceClient" should {
    "return 'Hello World!' on getData" in {
      val hello = sut.getData()
      hello must be equalTo("Hello World!")
    }
  }

}

class HelloResourceClient(target: WebTarget) {
  def getData() = {
    target.path("hello").request().get(classOf[String])
  }
}

That´s it. Have fun writing clients from now on!