Search code examples
scalascalatesttypesafe-config

Reading configuration files from unit tests


I have a very simply project.

build.sbt:

scalaVersion := "2.13.5"

lazy val testSettings = Seq(
  Test / javaOptions += "-Dconfig.resource=/test.conf"
)

libraryDependencies ++= Seq(
  "org.scalatest" %% "scalatest" % "3.2.3" % Test, 
  "com.typesafe" % "config" % "1.4.1"
)

Two configuration files under resources folder:

application.conf

some-value = "value from application.conf file"

test.conf

some-value = "value from test.conf file"

And only 1 spec test class:

SomeTestSpec:

class SomeTestSpec extends AnyFlatSpec with Matchers {
  val config: Config = ConfigFactory.load()

  "some test" should "read and print from test.conf" in {
    val value = config.getString("some-value")
    println(s"value of some-value = $value")

    value shouldBe "value from test.conf file"
  }
}

When I run the test if fails:

"value from [application].conf file" was not equal to "value from [test].conf file"
ScalaTestFailureLocation: SomeTestSpec at (SomeTestSpec.scala:12)
Expected :"value from [test].conf file"
Actual   :"value from [application].conf file"

Why the spec is reading the file application.conf instead of test.conf? Is something wrong in the build.sbt?:

lazy val testSettings = Seq(
  Test / javaOptions += "-Dconfig.resource=/test.conf"
)

Solution

  • The best practice is to place application.conf into src/main/resources/ for regular use and into src/test/resources/ for testing. You'll have 2 conf files with different values in test. If you don't need to change config for test you can simply keep one conf file in main.

    You don't have to override the file explicitly with -Dconfig.resource or -Dconfig.file for your tests because loading resources from class path will work as you expect out of the box and your test config will be used. -D option is mostly used at runtime to provide external configuration or in some complex build scenarios.

    If you use -Dconfig.resource or -Dconfig.file pay attention to the path. config.resource is just a filename, i.e. application.conf which will be loaded as resource while config.file is an absolute or relative file path.

    If you are making a library you can get fancy with reference.conf file having default values and application.conf overriding them. This could also work in your scenario but would be more confusing because that's not the purpose or reference file.

    For the purposes of testing just use 2 application.conf files.

    Additionally, here are some options to override config at runtime:

    Overriding multiple config values in Typesafe config when using an uberjar to deploy.

    Overriding configuration with environment variables in typesafe config

    Scala environment ${USER} in application.conf

    More info here: https://github.com/lightbend/config#standard-behavior