diff options
-rw-r--r-- | core/src/main/scala/com/softwaremill/sttp/testing/SttpBackendStub.scala | 36 | ||||
-rw-r--r-- | docs/testing.rst | 26 |
2 files changed, 53 insertions, 9 deletions
diff --git a/core/src/main/scala/com/softwaremill/sttp/testing/SttpBackendStub.scala b/core/src/main/scala/com/softwaremill/sttp/testing/SttpBackendStub.scala index 8a91e36..d816da6 100644 --- a/core/src/main/scala/com/softwaremill/sttp/testing/SttpBackendStub.scala +++ b/core/src/main/scala/com/softwaremill/sttp/testing/SttpBackendStub.scala @@ -5,6 +5,7 @@ import java.io.{File, InputStream} import com.softwaremill.sttp.testing.SttpBackendStub._ import com.softwaremill.sttp._ +import scala.concurrent.Future import scala.language.higherKinds import scala.util.{Failure, Success, Try} @@ -17,9 +18,13 @@ import scala.util.{Failure, Success, Try} * Note however, that this is not type-safe with respect to the type of the * response body - the stub doesn't have a way to check if the type of the * body in the configured response is the same as the one specified by the - * request. Hence, the predicates can match requests basing on the URI + * request. Some conversions will be attempted (e.g. from a `String` to + * a custom mapped type, as specified in the request, see the documentation + * for more details). + * + * Hence, the predicates can match requests basing on the URI * or headers. A [[ClassCastException]] might occur if for a given request, - * a response is specified with the incorrect body type. + * a response is specified with the incorrect or inconvertible body type. */ class SttpBackendStub[R[_], S] private (rm: MonadError[R], matchers: Vector[Matcher[_]], @@ -28,12 +33,21 @@ class SttpBackendStub[R[_], S] private (rm: MonadError[R], /** * Specify how the stub backend should respond to requests matching the - * given predicate. Note that the stubs are immutable, and each new + * given predicate. + * + * Note that the stubs are immutable, and each new * specification that is added yields a new stub instance. */ def whenRequestMatches(p: Request[_, _] => Boolean): WhenRequest = new WhenRequest(p) + /** + * Specify how the stub backend should respond to requests using the + * given partial function. + * + * Note that the stubs are immutable, and each new + * specification that is added yields a new stub instance. + */ def whenRequestMatchesPartial( partial: PartialFunction[Request[_, _], Response[_]]) : SttpBackendStub[R, S] = { @@ -88,6 +102,22 @@ class SttpBackendStub[R[_], S] private (rm: MonadError[R], object SttpBackendStub { /** + * Create a stub synchronous backend (which doesn't wrap results in any + * container), without streaming support. + */ + def synchronous: SttpBackendStub[Id, Nothing] = + new SttpBackendStub[Id, Nothing](IdMonad, Vector.empty, None) + + /** + * Create a stub asynchronous backend (which wraps results in Scala's + * built-in `Future`), without streaming support. + */ + def asynchronousFuture: SttpBackendStub[Future, Nothing] = { + import scala.concurrent.ExecutionContext.Implicits.global + new SttpBackendStub[Future, Nothing](new FutureMonad(), Vector.empty, None) + } + + /** * Create a stub backend for testing, which uses the same response wrappers * and supports the same stream type as the given "real" backend. * diff --git a/docs/testing.rst b/docs/testing.rst index 7332226..bb2e3d5 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -3,9 +3,20 @@ Testing If you need a stub backend for use in tests instead of a "real" backend (you probably don't want to make HTTP calls during unit tests), you can use the ``SttpBackendStub`` class. It allows specifying how the backend should respond to requests matching given predicates. -A backend stub can be created using an instance of a "real" backend, or by explicitly giving the response wrapper monad and supported streams type. +Creating a stub backend +----------------------- -For example:: +An empty backend stub can be created using the following ways: + +* given an instance of a "real" backend, e.g. ``SttpBackendStub(HttpURLConnectionBackend())`` or ``SttpBackendStub(AsyncHttpClientScalazBackend())``. The stub will then use the same response wrapper and support the same type of streams as the given "real" backend. +* by explicitly giving the response wrapper monad and supported streams type, e.g. ``SttpBackendStub[Task, Observable[ByteBuffer]](TaskMonad)`` +* by using one of the factory methods ``SttpBackendStub.synchronous`` or ``SttpBackendStub.asynchronousFuture``, which return stubs which use the ``Id`` or standard Scala's ``Future`` response wrappers without streaming support +* by specifying a fallback/delegate backend, see below + +Specifying behavior +------------------- + +Behavior of the stub can be specified using a combination of the ``whenRequestMatches`` and ``thenResponse`` methods:: implicit val testingBackend = SttpBackendStub(HttpURLConnectionBackend()) .whenRequestMatches(_.uri.path.startsWith(List("a", "b"))) @@ -23,8 +34,11 @@ It is also possible to match requests by partial function, returning a response. implicit val testingBackend = SttpBackendStub(HttpURLConnectionBackend()) .whenRequestMatchesPartial({ - case r if r.uri.path.endsWith(List("partial10")) => Response(Right(10), 200, Nil, Nil) - case r if r.uri.path.endsWith(List("partialAda")) => Response(Right("Ada"), 200, Nil, Nil) + case r if r.uri.path.endsWith(List("partial10")) => + Response(Right(10), 200, Nil, Nil) + + case r if r.uri.path.endsWith(List("partialAda")) => + Response(Right("Ada"), 200, Nil, Nil) }) val response1 = sttp.get(uri"http://example.org/partial10").send() @@ -33,7 +47,7 @@ It is also possible to match requests by partial function, returning a response. val response2 = sttp.post(uri"http://example.org/partialAda").send() // response2.body will be Right("Ada") -This approach to testing has one caveat: the responses are not type-safe. That is, the backend cannot match on or verify that the type included in the response matches the response type requested. +This approach to testing has one caveat: the responses are not type-safe. That is, the stub backend cannot match on or verify that the type of the response body matches the response body type requested. Simulating exceptions --------------------- @@ -71,7 +85,7 @@ For example:: .response(asByteArray.map(parseUserJson)) .send() -In the example above, the stub's rules specify that a response with a ``String``-body should be returned for any request; the request, on the other hand, specifies that responses should be parsed from a byte array to a custom ``User`` type. These type don't match, so the ``SttpBackendStub`` will in this case convert the body to the desired type. +In the example above, the stub's rules specify that a response with a ``String``-body should be returned for any request; the request, on the other hand, specifies that response body should be parsed from a byte array to a custom ``User`` type. These type don't match, so the ``SttpBackendStub`` will in this case convert the body to the desired type. Note that no conversions will be attempted for streaming response bodies. |