sbt test execution

Programmer
2 min readSep 16, 2019

--

How to tame sbt with OOM while running tests

Introduction

sbt is one of the official built tool for Scala. An attempt to setup running large number of tests on sbt can cause java.lang.OutOfMemoryError.

JVMDUMP039I Processing dump event "systhrow", detail "java/lang/OutOfMemoryError" at 2019/09/16 13:26:33 - please wait.
JVMDUMP032I JVM requested System dump using '/path/to/app/core.20190916.132633.8122.0001.dmp' in response to an event
JVMDUMP010I System dump written to /path/to/app/core.20190916.132633.8122.0001.dmp
JVMDUMP032I JVM requested Heap dump using '/path/to/app/heapdump.20190916.132633.8122.0002.phd' in response to an event
JVMDUMP010I Heap dump written to /path/to/app/heapdump.20190916.132633.8122.0002.phd
JVMDUMP032I JVM requested Java dump using '/path/to/app/javacore.20190916.132633.8122.0003.txt' in response to an event
JVMDUMP010I Java dump written to /path/to/app/javacore.20190916.132633.8122.0003.txt

I did run into OutofMemory issue when I was testing akka actor-typed using akka.actor.testkit.typed.

This is due to multiple reasons.

  • Parallel Execution
  • Forking
  • Grouping

Let’s try to understand each of this in better detail.

Parallel Execution

Parallel Execution enables sbt to run multiple tests simultaneously. This is generally a good default choice. But, there may be times when the unit tests are pretty heavy to run. During these cases, disabling this is a better choice.

Test / parallelExecution := false

Forking

By default, the run task runs in the same JVM as sbt. Forking is required under certain circumstances, however. Or, you might want to fork Java processes when implementing new tasks. (Source SBT documentation)

During the case when tests are pretty heavy, its best to run this in fork mode.

Test / fork := true

Grouping

Control over how tests are assigned to JVMs and what options to pass to those is available with testGrouping key

Grouping enables a way to size how much tests run in a single JVM. With forking enabled, all the tests run into a single forked JVMsequentially. This is reasonable. But, we would also like to say that every Test should spin as a brand new JVM.

Test / testGrouping := (definedTests in Test).value map { test =>
val options = ForkOptions().withRunJVMOptions(Vector.empty)
Tests.Group(
name = test.name,
tests = Seq(test),
runPolicy = Tests.SubProcess(options)
)
}

Source

https://www.scala-sbt.org/1.0/docs/Testing.html

--

--

Programmer
Programmer

No responses yet