diff --git a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/JUnitRouteTest.scala b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/JUnitRouteTest.scala index 039d47ee7b..97336f15b5 100644 --- a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/JUnitRouteTest.scala +++ b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/JUnitRouteTest.scala @@ -7,19 +7,20 @@ package akka.http.javadsl.testkit import akka.actor.ActorSystem import akka.http.javadsl.server._ import akka.http.scaladsl.model.HttpResponse -import akka.stream.ActorMaterializer +import akka.stream.{ Materializer, ActorMaterializer } import org.junit.rules.ExternalResource import org.junit.{ Assert, Rule } import scala.concurrent.duration._ /** - * A RouteTest that uses JUnit assertions. + * A RouteTest that uses JUnit assertions. ActorSystem and Materializer are provided as an [[ExternalResource]] + * and their lifetime is automatically managed. */ abstract class JUnitRouteTestBase extends RouteTest { protected def systemResource: ActorSystemResource implicit def system: ActorSystem = systemResource.system - implicit def materializer: ActorMaterializer = systemResource.materializer + implicit def materializer: Materializer = systemResource.materializer protected def createTestResponse(response: HttpResponse): TestResponse = new TestResponse(response, awaitDuration)(system.dispatcher, materializer) { @@ -32,7 +33,7 @@ abstract class JUnitRouteTestBase extends RouteTest { protected def assertTrue(predicate: Boolean, message: String): Unit = Assert.assertTrue(message, predicate) - protected def fail(message: String): Nothing = { + protected def fail(message: String): Unit = { Assert.fail(message) throw new IllegalStateException("Assertion should have failed") } diff --git a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/RouteTest.scala b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/RouteTest.scala index df660bd89a..a68bce8403 100644 --- a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/RouteTest.scala +++ b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/RouteTest.scala @@ -7,7 +7,7 @@ package akka.http.javadsl.testkit import scala.annotation.varargs import scala.concurrent.ExecutionContext import scala.concurrent.duration._ -import akka.stream.ActorMaterializer +import akka.stream.Materializer import akka.http.scaladsl.server import akka.http.javadsl.model.HttpRequest import akka.http.javadsl.server.{ HttpApp, AllDirectives, Route, Directives } @@ -19,9 +19,17 @@ import akka.actor.ActorSystem import akka.event.NoLogging import akka.http.impl.util._ +/** + * A base class to create route tests for testing libraries. An implementation needs to provide + * code to provide and shutdown an [[ActorSystem]], [[Materializer]], and [[ExecutionContext]]. + * Also an implementation should provide instances of [[TestResponse]] to define the assertion + * facilities of the testing library. + * + * See `JUnitRouteTest` for an example of a concrete implementation. + */ abstract class RouteTest extends AllDirectives { implicit def system: ActorSystem - implicit def materializer: ActorMaterializer + implicit def materializer: Materializer implicit def executionContext: ExecutionContext = system.dispatcher protected def awaitDuration: FiniteDuration = 500.millis @@ -53,7 +61,7 @@ abstract class RouteTest extends AllDirectives { /** * Creates a [[TestRoute]] for the main route of an [[HttpApp]]. */ - def testAppRoute(app: HttpApp): TestRoute = testRoute(app.createRoute) + def testAppRoute(app: HttpApp): TestRoute = testRoute(app.createRoute()) protected def createTestResponse(response: HttpResponse): TestResponse } diff --git a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/TestResponse.scala b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/TestResponse.scala index fcf052844f..20614bc85d 100644 --- a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/TestResponse.scala +++ b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/TestResponse.scala @@ -8,7 +8,7 @@ import scala.reflect.ClassTag import scala.concurrent.ExecutionContext import scala.concurrent.duration.FiniteDuration import akka.util.ByteString -import akka.stream.ActorMaterializer +import akka.stream.Materializer import akka.http.scaladsl.unmarshalling.Unmarshal import akka.http.scaladsl.model.HttpResponse import akka.http.impl.util._ @@ -18,9 +18,12 @@ import akka.http.javadsl.server.Unmarshaller import akka.http.javadsl.model._ /** - * A wrapper for responses + * A wrapper for responses. + * + * To support the testkit API, a third-party testing library needs to implement this class and provide + * implementations for the abstract assertion methods. */ -abstract class TestResponse(_response: HttpResponse, awaitAtMost: FiniteDuration)(implicit ec: ExecutionContext, materializer: ActorMaterializer) { +abstract class TestResponse(_response: HttpResponse, awaitAtMost: FiniteDuration)(implicit ec: ExecutionContext, materializer: Materializer) { /** * Returns the strictified entity of the response. It will be strictified on first access. */ @@ -75,7 +78,7 @@ abstract class TestResponse(_response: HttpResponse, awaitAtMost: FiniteDuration */ def header[T <: HttpHeader](clazz: Class[T]): T = response.header(ClassTag(clazz)) - .getOrElse(fail(s"Expected header of type ${clazz.getSimpleName} but wasn't found.")) + .getOrElse(doFail(s"Expected header of type ${clazz.getSimpleName} but wasn't found.")) /** * Assert on the numeric status code. @@ -150,7 +153,7 @@ abstract class TestResponse(_response: HttpResponse, awaitAtMost: FiniteDuration } private[this] def extractFromResponse[T](f: HttpResponse ⇒ T): T = - if (response eq null) fail("Request didn't complete with response") + if (response eq null) doFail("Request didn't complete with response") else f(response) protected def assertEqualsKind(expected: AnyRef, actual: AnyRef, kind: String): TestResponse = { @@ -162,7 +165,13 @@ abstract class TestResponse(_response: HttpResponse, awaitAtMost: FiniteDuration this } - protected def fail(message: String): Nothing + // allows to `fail` as an expression + private def doFail(message: String): Nothing = { + fail(message) + throw new IllegalStateException("Shouldn't be reached") + } + + protected def fail(message: String): Unit protected def assertEquals(expected: AnyRef, actual: AnyRef, message: String): Unit protected def assertEquals(expected: Int, actual: Int, message: String): Unit protected def assertTrue(predicate: Boolean, message: String): Unit diff --git a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/TestRoute.scala b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/TestRoute.scala index 68d329e396..be03da323e 100644 --- a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/TestRoute.scala +++ b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/TestRoute.scala @@ -7,6 +7,14 @@ package akka.http.javadsl.testkit import akka.http.javadsl.model.HttpRequest import akka.http.javadsl.server.Route +/** + * A wrapped route that has a `run` method to run a request through the underlying route to create + * a [[TestResponse]]. + * + * A TestRoute is created by deriving a test class from the concrete RouteTest implementation for your + * testing framework (like [[JUnitRouteTest]] for JUnit) and then using its `testRoute` method to wrap + * a route with testing support. + */ trait TestRoute { def underlying: Route def run(request: HttpRequest): TestResponse