Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test async scala code

Experimenting with concurrent execution I was wondering how to actually test it. The execution flow is of a side-effect nature and futures are created to wrap independent executions/processing.

Been searching for some good examples on how to properly unit test the following scenarios (foo and bar are the methods I wish to test):

scenario #1

def foo : Unit = {
    Future { doSomething }
    Future { doSomethingElse }
}

private def doSomething : Unit = serviceCall1
private def doSomethingElse : Unit = serviceCall2

Scenario motivation

foo immediately returns but invokes 2 futures which perform separate tasks (e.g. save analytics and store record to DB). These service calls can be mocked, but what I'm trying to test is that both these services are called once I wrap them in Futures

scenario #2

def bar : Unit = {
    val futureX = doAsyncX
    val futureY = doAsyncY
    for {
        x <- futureX
        y <- futureY
    } yield {
        noOp(x, y)
    }
}

Scenario motivation

Start with long running computations that can be executed concurrently (e.g. get the number of total visitors and get the frequently used User-Agent header to our web site). Combine the result in some other operation (which in this case Unit method that simply throws the values)

Note I'm familiar with actors and testing actors, but given the above code I wonder what should be the most suitable approach (refactoring included)

EDIT What I'm doing at the moment

implicit value context = ExecutionContext.fromExecutor(testExecutor)

def testExecutor = {
    new Executor {
        def execute(runnable : Runnable) = runnable.run
    }
}

This ExecutionContext implementation will not run the Future as a separate thread and the entire execution will be done in sequence. This kinda feels like a hack but based on Electric Monk answer, it seems like the other solution is more of the same.

like image 702
Bivas Avatar asked Aug 06 '14 19:08

Bivas


2 Answers

One solution would be to use a DeterministicExecutor. Not a scalaesque solution, but should so the trick.

like image 191
Electric Monk Avatar answered Oct 16 '22 05:10

Electric Monk


If you are using ScalaTest, take a look at: http://doc.scalatest.org/2.0/index.html#org.scalatest.concurrent.Futures

Specs2 also has support for testing Futures: http://etorreborre.github.io/specs2/guide/org.specs2.guide.Matchers.html

like image 28
Sudheer Aedama Avatar answered Oct 16 '22 04:10

Sudheer Aedama