1. Introduction

SBT is the de facto build tool for Scala applications. In this tutorial, we’ll understand the ways in which we can filter tests and run them through sbt.

2. Running Tests in SBT

SBT assumes the code is structured in a particular way. Specifically, we use the directory structure src/main/scala for the main sources and src/test/scala for the test classes. We can compile the main sources without compiling the tests using the command:

sbt compile

We can also compile only the tests:

sbt test:compile

This compiles all the files under the path src/test/scala.

Consequently, we can run all the tests in a project:

sbt test

This executes all the tests within the test directory across all submodules.

3. Filter Tests to Run

When we don’t want to run all the tests, we can run a subset of the them using different filtering techniques. SBT provides multiple ways to filter the tests. We’ll look into the most common ways in this section.

3.1. Using testOnly Command

We can run only a particular test using the testOnly command:

sbt test:testOnly com.baeldung.munit.MUnitTest

This executes all the tests within the MUnitTest class alone. We should note that we need to give the full path of the test class. Otherwise, it won’t execute any tests.

We can also use the wildcard search in the testOnly command, which runs only the matched tests. We can run the MUniteTest without giving the full package path using the wildcard:

test:testOnly *MUnitTest

This runs all the tests in classes with names that end with MUnitTest, across all packages. This executes tests in classes named MUnitTest, AnotherMUnitTest, and so on.

Similarly, we can run all the tests under a package using the wildcard in the package path:

test:testOnly com.baeldung.scala.either.*

This runs all the tests in the package com.baeldung.scala.either and its sub-packages.

3.2. Using Tests.Filter in Test Options

Another way to filter tests to run is by using the test options. Test options are the properties we can set for the tests. We can filter the tests using the Filter method provided by SBT.

Let’s look at how we can set a test option. We can add the filter condition in build.sbt:

ThisBuild / Test / testOptions := Seq(Tests.Filter(testClass => testClass.endsWith("UnitTest")))

With this, when we run the command test, SBT executes only the test classes whose name ends with UnitTest. All other tests are ignored. In the above example, the variable testClass contains the full path of the test class, including the package name. Since it’s a string value, we can apply any String operations on it, such as endsWith, contains, equals, and so on.

The disadvantage of this approach is that even if we add more tests, they will be ignored if the class name doesn’t end with UnitTest. Moreover, this applies to the entire project or the sub-module, depending on where it is defined.

3.3. Using Test.Filter With an Alias

We noticed that adding the testOptions directly on build.sbt affects the entire project. To overcome this, we can use testOptions along with SBT command aliases. Let’s see how we can provide testOptions with an alias and how it can overcome the previous issue:

addCommandAlias(
  "onlyUnitTests",
  """; set ThisBuild/Test/testOptions += Tests.Filter(t => t.endsWith("UnitTest")); test""".stripMargin
)

Here, we defined the testOptions as part of the alias definition. As a result, the test filter is applicable only during the alias invocation.

We can execute the alias command just like any other sbt command:

sbt onlyUnitTests

When we execute this command, it runs only the tests that end with UnitTest in their name. Moreover, when we execute the command sbt test, it runs all the tests without applying the filter condition. This way, we can filter the tests without affecting the entire project.

4. Conclusion

In this article, we looked at different ways to filter and execute tests in SBT. Additionally, we also discussed the use of aliases to better arrange the tests for different executions.

As always, the sample commands used in this article are available over on GitHub.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.