aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/testing/SttpBackendStub.scala36
-rw-r--r--docs/testing.rst26
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.