aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradamw <adam@warski.org>2017-11-13 13:40:11 +0100
committeradamw <adam@warski.org>2017-11-13 13:40:11 +0100
commit927c7c73b9766e825e1949667219ee367f342054 (patch)
tree4ae371ee30f40395b4f0cf721b816c2f01a7e07b
parent9635a25aeead9d56e9f8b34518df19746e81967d (diff)
downloadsttp-927c7c73b9766e825e1949667219ee367f342054.tar.gz
sttp-927c7c73b9766e825e1949667219ee367f342054.tar.bz2
sttp-927c7c73b9766e825e1949667219ee367f342054.zip
#43: supporting exceptions in the stub backend
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/testing/SttpBackendStub.scala12
-rw-r--r--core/src/test/scala/com/softwaremill/sttp/testing/SttpBackendStubTests.scala23
-rw-r--r--docs/backends/testing.rst12
3 files changed, 41 insertions, 6 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 f62959f..b894e77 100644
--- a/core/src/main/scala/com/softwaremill/sttp/testing/SttpBackendStub.scala
+++ b/core/src/main/scala/com/softwaremill/sttp/testing/SttpBackendStub.scala
@@ -4,6 +4,7 @@ import com.softwaremill.sttp.testing.SttpBackendStub._
import com.softwaremill.sttp.{MonadError, Request, Response, SttpBackend}
import scala.language.higherKinds
+import scala.util.{Failure, Success, Try}
/**
* A stub backend to use in tests.
@@ -42,9 +43,10 @@ class SttpBackendStub[R[_], S] private (rm: MonadError[R],
matchers
.collectFirst {
case matcher: Matcher[T @unchecked] if matcher(request) =>
- matcher.response(request).get
+ Try(matcher.response(request).get)
} match {
- case Some(response) => wrapResponse(response)
+ case Some(Success(response)) => wrapResponse(response)
+ case Some(Failure(e)) => rm.error(e)
case None =>
fallback match {
case None => wrapResponse(DefaultResponse)
@@ -72,10 +74,9 @@ class SttpBackendStub[R[_], S] private (rm: MonadError[R],
thenRespond(Response[Nothing](Left(msg), code, Nil, Nil))
def thenRespond[T](body: T): SttpBackendStub[R, S] =
thenRespond(Response[T](Right(body), 200, Nil, Nil))
- def thenRespond[T](resp: Response[T]): SttpBackendStub[R, S] = {
+ def thenRespond[T](resp: => Response[T]): SttpBackendStub[R, S] = {
val m = Matcher[T](p, resp)
new SttpBackendStub(rm, matchers :+ m, fallback)
-
}
}
}
@@ -124,8 +125,7 @@ object SttpBackendStub {
}
private object Matcher {
-
- def apply[T](p: Request[T, _] => Boolean, response: Response[T]) = {
+ def apply[T](p: Request[T, _] => Boolean, response: => Response[T]) = {
new Matcher[T]({
case r if p(r) => response
})
diff --git a/core/src/test/scala/com/softwaremill/sttp/testing/SttpBackendStubTests.scala b/core/src/test/scala/com/softwaremill/sttp/testing/SttpBackendStubTests.scala
index 9e10cd7..292d324 100644
--- a/core/src/test/scala/com/softwaremill/sttp/testing/SttpBackendStubTests.scala
+++ b/core/src/test/scala/com/softwaremill/sttp/testing/SttpBackendStubTests.scala
@@ -1,5 +1,9 @@
package com.softwaremill.sttp.testing
+import java.util.concurrent.TimeoutException
+
+import scala.concurrent.ExecutionContext.Implicits.global
+
import com.softwaremill.sttp._
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.{FlatSpec, Matchers}
@@ -70,6 +74,25 @@ class SttpBackendStubTests extends FlatSpec with Matchers with ScalaFutures {
ada.body should be(Right("Ada"))
}
+ it should "handle exceptions thrown instead of a response (synchronous)" in {
+ implicit val s = SttpBackendStub(HttpURLConnectionBackend())
+ .whenRequestMatches(_ => true)
+ .thenRespond(throw new TimeoutException())
+
+ a[TimeoutException] should be thrownBy {
+ sttp.get(uri"http://example.org").send()
+ }
+ }
+
+ it should "handle exceptions thrown instead of a response (asynchronous)" in {
+ implicit val s = SttpBackendStub(new FutureMonad())
+ .whenRequestMatches(_ => true)
+ .thenRespond(throw new TimeoutException())
+
+ val result = sttp.get(uri"http://example.org").send()
+ result.failed.futureValue shouldBe a[TimeoutException]
+ }
+
val testingStubWithFallback = SttpBackendStub
.withFallback(testingStub)
.whenRequestMatches(_.uri.path.startsWith(List("c")))
diff --git a/docs/backends/testing.rst b/docs/backends/testing.rst
index 1618d68..d1e99da 100644
--- a/docs/backends/testing.rst
+++ b/docs/backends/testing.rst
@@ -35,6 +35,18 @@ It is also possible to match request by partial function, returning a response.
However, this approach 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.
+Simulating exceptions
+---------------------
+
+If you want to simulate an exception being thrown by a backend, e.g. a socket timeout exception, you can do so by throwing the appropriate exception instead of the response, e.g.::
+
+ implicit val testingBackend = SttpBackendStub(HttpURLConnectionBackend())
+ .whenRequestMatches(_ => true)
+ .thenRespond(throw new TimeoutException())
+
+Delegating to another backend
+-----------------------------
+
It is also possible to create a stub backend which delegates calls to another (possibly "real") backend if none of the specified predicates match a request. This can be useful during development, to partially stub a yet incomplete API with which we integrate::
implicit val testingBackend =