fs2-queues

Testing

The testing module provides tools to write unit tests for code base using the fs2-queues library.

libraryDependencies += "com.commercetools" %% "fs2-queues-testing" % "0.5.0"

Using TestQueue

The TestQueue class implements an in-memory queue system. A TestQueue can be wrapped to create a:

The TestQueue and the various test tools are designed to work well when used with the cats-effect test runtime

For instance, if you want to test code that needs to publish with delays, you can use the following approach:

import com.commercetools.queue.testing._

import scala.concurrent.duration._

import cats.effect._
import cats.effect.testkit._
import cats.effect.unsafe.implicits.global

TestQueue[String](name = "test-queue", messageTTL = 10.minutes, lockTTL = 1.minute)
  .flatMap { testQueue =>
    val puller = TestQueuePuller(testQueue)  
    val pusher = TestQueuePusher(testQueue)  

    val program =
      for {
        _ <- pusher.push("one", Map.empty, Some(10.seconds))
        immediatelyPulled <- puller.pullBatch(10, Duration.Zero)
        _ <- IO.sleep(11.seconds)
        laterPulled <- puller.pullBatch(10, Duration.Zero)
      } yield (immediatelyPulled.size, laterPulled.size)

    TestControl.executeEmbed(program)
  }
  .unsafeRunSync()
// res0: (Int, Int) = (0, 1)

Using custom effects

You might want to use a custom effect in your unit test, instead of a full blown queue implementation. For instance, if you want to test the behavior of a failing push, you can use the following approach:

val pusher = TestQueuePusher.fromPush[String]((_, _, _) => IO.raiseError(new Exception("BOOM!")))

pusher.push("test message", Map.empty, None).unsafeRunSync()
// java.lang.Exception: BOOM!
// 	at repl.MdocSession$MdocApp$$anonfun$3$$anonfun$4.apply(testing.md:45)
// 	at repl.MdocSession$MdocApp$$anonfun$3$$anonfun$4.apply(testing.md:45)
// 	at com.commercetools.queue.testing.TestQueuePusher$$anon$1.push(TestQueuePusher.scala:52)
// 	at com.commercetools.queue.testing.TestQueuePusher$$anon$1.push(TestQueuePusher.scala:47)
// 	at repl.MdocSession$MdocApp$$anonfun$3.apply$mcV$sp(testing.md:46)
// 	at repl.MdocSession$MdocApp$$anonfun$3.apply(testing.md:44)
// 	at repl.MdocSession$MdocApp$$anonfun$3.apply(testing.md:44)

The provided function takes the same parameters as the QueuePusher.push method for a single message and can return any effect.

These variants are available on test entities.

Testing message contexts

If you need to unit test different behavior on message contexts, you can use the TestingMessageContext class. It allows you to create a message context with different behaviors.

For instance, if you want to check the behavior of a failing ack on a message, you can use this approach:

val ctx = TestingMessageContext("payload").failing(new Exception("BOOM!"))

ctx.ack().unsafeRunSync()
// java.lang.Exception: BOOM!
// 	at repl.MdocSession$MdocApp$$anonfun$5.apply$mcV$sp(testing.md:56)
// 	at repl.MdocSession$MdocApp$$anonfun$5.apply(testing.md:55)
// 	at repl.MdocSession$MdocApp$$anonfun$5.apply(testing.md:55)