Skip to main content
Version: 6.2 🚧

Project Level Config

danger

This document describes project-level configuration in Kotest 6.0. If you were using project-level configuration in Kotest 5.x, note that the behavior has changed. Please read these docs carefully to ensure the config classes are picked up by the framework.

Kotest is flexible and has many ways to configure tests, such as configuring the order of tests inside a spec or how test classes are created. Sometimes you may want to set this at a global level, and for that you need to use project wide config.

Project wide configuration can be used by creating a class that extends from AbstractProjectConfig. On JVM and JS platforms, an object is also supported if you prefer using an object to a class.

Any configuration set at a spec level or directly on a test will override config specified at the project level. Some configuration options are only available at the project level because they change how the test engine runs the entire test suite (for example, the max number of concurrent specs to execute wouldn't make any sense to be specified at the spec level).

Some configuration options available in AbstractProjectConfig include assertions modes, timeouts, failing specs with ignored tests, global AssertSoftly, and reusable listeners or extensions and so on.

Setup​

The behavior differs depending on if you are using Kotest on the JVM, or on non-JVM platforms like Kotlin native or JS. Always the class must extend AbstractProjectConfig.

JVM​

On the JVM, there are three locations that Kotest will inspect looking for a config class. These are:

  • a class with the fully qualified name io.kotest.provided.ProjectConfig
  • a class with a fully qualified name specified by the system property kotest.framework.config.fqn
  • a class named ProjectConfig that exists in any common package of all tests.

Firstly, Kotest will inspect the classpath for a class at io.kotest.provided.ProjectConfig. If that class exists, it will be instantiated and used.

Secondly, if the system property kotest.framework.config.fqn is set, then the value of that property will be used to locate a class with that fully qualified name. If that class exists, it will be instantiated and used. Note that in Gradle, you must propagate the system property to the JVM process by setting the systemProperty property on the Gradle test task. For example:

tests.task {
useJunitPlatform()
systemProperty("kotest.framework.config.fqn", "com.sksamuel.mypackage.MyConfigClass")
}

Finally, you can place your config class in any package that is common to all tests. For example, if you have tests located in com.sksamuel.myproject.services, com.sksamuel.myproject.common, and com.sksamuel.myproject.data, then you can place your config class in any of com.sksamuel.myproject, com.sksamuel, and com.

note

The common package search is only available in Kotest 6.2+

Non-JVM​

On Kotlin native and JS platforms, the config class can be located anywhere but must still extend AbstractProjectConfig.

caution

You should only create a single project config class, otherwise the behavior is undefined. If you want to have different configurations per package, see package level config.

Examples​

Assertion Mode​

You can ask Kotest to fail the build or warn in stderr, if a test is executed that does not use a Kotest assertion.

To do this, set assertionMode to AssertionMode.Error or AssertionMode.Warn inside your config. For example. An alternative way to enable this is the system property kotest.framework.assertion.mode which will always (if defined) take priority over the value here.

object KotestProjectConfig : AbstractProjectConfig() {
override val assertionMode = AssertionMode.Error
}
caution

Assertion mode only works for Kotest assertions and not other assertion libraries. This is because the assertions need to be aware of the assertion detection framework that Kotest provides.

Global Assert Softly​

Assert softly is very useful to batch up errors into a single failure. If we want to enable this for every test automatically, we can do this in a config. An alternative way to enable this is by setting system property kotest.framework.assertion.globalassertsoftly to true which will always (if defined) take priority over the value here.

object KotestProjectConfig : AbstractProjectConfig() {
override val globalAssertSoftly = true
}

Timeouts​

You can set a default timeout for all tests in your project by setting the timeout property in your project config.

object KotestProjectConfig : AbstractProjectConfig() {
override val timeout = 5.seconds
}

Duplicate Test Name Handling​

By default, Kotest will rename a test if it has the same name as another test in the same scope. It will append _1, _2 and so on to the test name. This is useful for automatically generated tests.

You can change this behavior globally by setting duplicateTestNameMode to either DuplicateTestNameMode.Error or DuplicateTestNameMode.Warn.

Error will fail the test suite on a repeated name, and warn will rename but output a warning.

Fail On Ignored Tests​

You may wish to consider an ignored test as a failure. To enable this feature, set failOnIgnoredTests to true inside your project config. For example.

object KotestProjectConfig : AbstractProjectConfig() {
override val failOnIgnoredTests = true
}

Ordering​

Kotest supports ordering both specs and tests independently.

Test Ordering​

When running multiple tests from a Spec, there's a certain order on how to execute them.

By default, a sequential order is used (the order that tests are defined in the spec), but this can be changed. For available options see test ordering.

Spec Ordering​

By default, the ordering of Spec classes is not defined. This is often sufficient, when we have no preference, but if we need control over the execution order of specs, we can use spec ordering.

Test Naming​

Test names can be adjusted in several ways.

Test Case​

Test names case can be controlled by changing the value of testNameCase.

By default, the value is TestNameCase.AsIs which makes no change.

By setting the value to TestNameCase.Lowercase a test's name will be lowercase in output.

If you are using a spec that adds in prefixes to the test names (should as WordSpec or BehaviorSpec) then the values TestNameCase.Sentence and TestNameCase.InitialLowercase can be useful.

Test Name Tags​

Another using test name option is testNameAppendTags which, when set to true, will include any applicable tags in the test name. For example, if a test foo was defined in a spec with the tags linux and spark then the test name would be adjusted to be foo [linux, spark]

This setting can also be set using a system property or environment variable kotest.framework.testname.append.tags to true.

Test name whitespace​

If you define test names over several lines then removeTestNameWhitespace can be useful. Take this example:

"""this is
my test case""" {
// test here
}

Then the test name in output will be this is _ _ _ my test case (note: the underscores are added for emphasis). By setting removeTestNameWhitespace to true, then this name will be trimmed to this is my test case.

An alternative way to enable this is by setting system property kotest.framework.testname.multiline to true which will always (if defined) take priority over the value here.

object KotestProjectConfig : AbstractProjectConfig() {
override val testNameRemoveWhitespace = true
}

Coroutine Dispatcher Factory​

You can specify a custom coroutine dispatcher factory to control how coroutines are executed in your tests.

object KotestProjectConfig : AbstractProjectConfig() {
override val coroutineDispatcherFactory = ThreadPerSpecCoroutineContextFactory
}

For more details on this feature, see the concurrency documentation.