Scalatest Async style

I posted this in the Scalatest discussion list, but I don’t think it’s much alive. Maybe someone here can hep me.

I’m trying to rewrite some FunSuite tests I have using AsyncFunSuite and I have a few questions.

Suppose I want to test an object for thread-safety (an atomic integer in my example):

  test("a single-thread future test") {
    val n = 32
    val range = 1 to n
    val shared = new AtomicInteger()
    val f = Future.traverse(range)(_ => Future(shared.incrementAndGet()))
    for (l <- f) yield {
      assert(shared.get === n)
      assert(l.toSet === range.toSet)
    }
  }

Given the default behavior of Async, this only tests my atomic integer using a single thread, which is not very exciting. I can write a more interesting test like this:

  test("a multi-threaded future test") {
    implicit val exec: ExecutionContextExecutorService =
      ExecutionContext.fromExecutorService(Executors.newCachedThreadPool)
    val n = 32
    val range = 1 to n
    val shared = new AtomicInteger()
    val ready = new CountDownLatch(n)
    val f = Future.traverse(range) { _ =>
      Future {
        ready.countDown()
        ready.await()
        shared.incrementAndGet()
      }
    }
    for (l <- f) yield {
      exec.shutdown()
      assert(shared.get === n)
      assert(l.toSet === range.toSet)
    }
  }

(I’m not overriding the default executor because I envision different executors for different tests.)

My questions:

  1. (this is more of a general Scala question) I cannot have an implicit exec of type ExecutionContext inside the test because it leads to ambiguous implicit resolution. Shouldn’t an implicit in a narrower scope shadow the other one? What’s the workaround?

  2. My test looks just like it did before, with all the concurrency setting done by hand. Does AsyncFunSuite offer useful mechanisms for that, which I missed?

  3. If not, the only difference with my previous test in FunSuite is that I can omit the line at the end:

     awaitFutures(timeout)(g)
    

    where awaitFutures is a little function I wrote (and g is the value produced by for/yield). Is that it? What am I getting from switching from FunSuite to AsyncFunSuite besides not having to wait for my futures explicitly? Is there a suitable Async style for the kind of concurrency test above?

  4. My awaitFutures lets me specify a timeout. Is that even possible if I use AsyncFunSuite?

Thanks,

MC

1 Like

I agree. And so do the Dotty developers apparently. The workaround they use for compiling their Dotty compiler with scalac is always using the same name for their implicits of the same type, so the names shadow each other even if the types don’t:

Welcome to Scala 2.12.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_152).
Type in expressions for evaluation. Or try :help.

scala> case class Foo(i: Int)
defined class Foo

scala> def foo(implicit f: Foo) = {
     |   def bar(implicit f: Foo) = println(implicitly[Foo])
     |   bar(Foo(2))
     | }
foo: (implicit foo: Foo)Unit

scala> foo(Foo(1))
Foo(2)
1 Like