scala-testing
Scala testing with ScalaTest, MUnit, and ScalaCheck: FunSpec/FlatSpec test structure, property-based testing with forAll, mocking with MockitoSugar, Cats Effect testing with munit-cats-effect (runTest/IOSuite), ZIO Test, Testcontainers-Scala for database integration tests, and CI integration with sbt. Use when writing or reviewing Scala tests.
Best use case
scala-testing is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Scala testing with ScalaTest, MUnit, and ScalaCheck: FunSpec/FlatSpec test structure, property-based testing with forAll, mocking with MockitoSugar, Cats Effect testing with munit-cats-effect (runTest/IOSuite), ZIO Test, Testcontainers-Scala for database integration tests, and CI integration with sbt. Use when writing or reviewing Scala tests.
Teams using scala-testing should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/scala-testing/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How scala-testing Compares
| Feature / Agent | scala-testing | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Scala testing with ScalaTest, MUnit, and ScalaCheck: FunSpec/FlatSpec test structure, property-based testing with forAll, mocking with MockitoSugar, Cats Effect testing with munit-cats-effect (runTest/IOSuite), ZIO Test, Testcontainers-Scala for database integration tests, and CI integration with sbt. Use when writing or reviewing Scala tests.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
SKILL.md Source
# Scala Testing
## When to Activate
- Writing tests for Scala code
- Choosing a Scala test framework
- Testing Cats Effect or ZIO code
- Setting up integration tests with real databases
- Adding property-based tests with ScalaCheck to cover edge cases automatically
- Configuring Testcontainers for a PostgreSQL or other database in CI
- Reviewing test coverage and deciding between unit fakes and Mockito mocks
---
## ScalaTest
Standard, feature-rich framework. Prefer `AnyFunSpec` or `AnyFlatSpec`.
### AnyFunSpec — BDD-style
```scala
import org.scalatest.funspec.AnyFunSpec
import org.scalatest.matchers.should.Matchers
class UserServiceSpec extends AnyFunSpec with Matchers:
describe("UserService"):
describe("find"):
it("returns Some when user exists"):
val repo = InMemoryUserRepo(Map(userId -> user))
val svc = UserService(repo)
svc.find(userId) shouldBe Some(user)
it("returns None when user not found"):
val svc = UserService(InMemoryUserRepo())
svc.find(userId) shouldBe None
```
### AnyFlatSpec — simpler style
```scala
class UserServiceSpec extends AnyFlatSpec with Matchers:
"UserService.find" should "return Some for existing user" in {
UserService(repo).find(userId) shouldBe Some(user)
}
it should "return None for missing user" in {
UserService(InMemoryUserRepo()).find(userId) shouldBe None
}
```
### Matchers Reference
```scala
result shouldBe Some(user) // equality
result should not be empty
result shouldEqual List(1, 2, 3)
name should startWith("Alice")
list should have length 3
n should be > 0
thrown.getMessage should include("not found")
// Exception testing
an [IllegalArgumentException] should be thrownBy {
validateAge(-1)
}
```
---
## MUnit — Lightweight and Fast
Recommended for new projects. Simpler setup, compatible with Cats Effect.
```scala
import munit.FunSuite
class UserSuite extends FunSuite:
test("find returns Some for existing user"):
val svc = UserService(InMemoryUserRepo(Map(userId -> user)))
assertEquals(svc.find(userId), Some(user))
test("find returns None for missing user"):
assertEquals(
UserService(InMemoryUserRepo()).find(userId),
None
)
```
---
## Property-Based Testing — ScalaCheck
Test invariants across random inputs:
```scala
import org.scalacheck.{Gen, Prop}
import org.scalacheck.Prop.forAll
object EmailSpec extends org.scalacheck.Properties("Email"):
val validEmail: Gen[String] =
for
user <- Gen.alphaStr.suchThat(_.nonEmpty)
domain <- Gen.alphaStr.suchThat(_.nonEmpty)
yield s"$user@$domain.com"
property("encode then decode roundtrip") = forAll { (s: String) =>
Email.parse(Email.format(s)) == s
}
property("valid emails always parse") = forAll(validEmail) { email =>
Email.parse(email).isRight
}
```
### MUnit + ScalaCheck
```scala
import munit.ScalaCheckSuite
import org.scalacheck.Prop.*
class SlugSuite extends ScalaCheckSuite:
property("slug is always lowercase"):
forAll { (s: String) =>
val slug = s.toSlug
slug == slug.toLowerCase
}
```
---
## Cats Effect Testing — munit-cats-effect
```scala
import munit.CatsEffectSuite
import cats.effect.IO
class UserRepoSuite extends CatsEffectSuite:
test("save and retrieve user"):
for
repo <- IO(InMemoryUserRepo())
_ <- repo.save(user)
result <- repo.find(user.id)
yield assertEquals(result, Some(user))
test("concurrent saves are safe"):
for
repo <- IO(InMemoryUserRepo())
_ <- (1 to 100).toList.parTraverse(i => repo.save(user.copy(id = UserId(i.toString))))
all <- repo.findAll
yield assertEquals(all.size, 100)
```
### Resource Fixtures
```scala
val dbRepo: Fixture[UserRepo] =
ResourceSuiteLocalFixture("db-repo",
Resource.make(IO(PostgresUserRepo(testPool)))(r => IO(r.close()))
)
override def munitFixtures = List(dbRepo)
test("saves to Postgres"):
dbRepo().save(user) >> dbRepo().find(user.id).map:
result => assertEquals(result, Some(user))
```
---
## ZIO Test
```scala
import zio.test.*
import zio.test.Assertion.*
object UserServiceSpec extends ZIOSpecDefault:
def spec = suite("UserService")(
test("find returns user when exists"):
for
svc <- ZIO.service[UserService]
result <- svc.find(userId)
yield assert(result)(isSome(equalTo(user)))
).provide(
UserService.live,
InMemoryUserRepo.layer
)
```
---
## Mocking with MockitoSugar
Prefer **fakes** (in-memory implementations) over mocks when possible.
When mocking is necessary:
```scala
import org.mockito.MockitoSugar
import org.mockito.ArgumentMatchers.any
class PaymentServiceSpec extends AnyFunSpec with MockitoSugar:
val gateway = mock[PaymentGateway]
describe("charge"):
it("calls gateway with correct amount"):
when(gateway.charge(any[Amount])) thenReturn IO.pure(PaymentResult.Success("tx-1", amount))
val svc = PaymentService(gateway)
svc.charge(amount).unsafeRunSync()
verify(gateway).charge(amount)
```
---
## Testcontainers — Integration Tests
```scala
import com.dimafeng.testcontainers.{PostgreSQLContainer, ForAllTestContainer}
class PostgresRepoSpec extends AnyFunSpec with ForAllTestContainer:
override val container = PostgreSQLContainer("postgres:16")
lazy val repo = PostgresUserRepo(
jdbcUrl = container.jdbcUrl,
username = container.username,
password = container.password
)
describe("PostgresUserRepo"):
it("persists and retrieves user"):
repo.save(user)
repo.find(user.id) shouldBe Some(user)
```
### MUnit + Testcontainers
```scala
class DbSuite extends CatsEffectSuite:
val pg = ResourceSuiteLocalFixture("postgres",
Resource.fromAutoCloseable(IO(PostgreSQLContainer("postgres:16").tap(_.start())))
)
override def munitFixtures = List(pg)
test("saves to real postgres"):
val repo = PostgresUserRepo.fromContainer(pg())
repo.save(user) >> repo.find(user.id).map(assertEquals(_, Some(user)))
```
---
## Test Organization
```
src/
test/
scala/
com/example/
UserServiceSpec.scala # Unit — pure, no I/O
UserRepoSpec.scala # Integration — Testcontainers
PaymentServiceProperties.scala # ScalaCheck properties
```
## Build Configuration
```scala
// build.sbt
libraryDependencies ++= Seq(
"org.scalameta" %% "munit" % "1.0.0" % Test,
"org.typelevel" %% "munit-cats-effect" % "2.0.0" % Test,
"org.scalatest" %% "scalatest" % "3.2.18" % Test,
"org.scalacheck" %% "scalacheck" % "1.17.0" % Test,
"org.mockito" %% "mockito-scala" % "1.17.31"% Test,
"com.dimafeng" %% "testcontainers-scala-postgresql" % "0.41.4" % Test
)
```
## Running Tests
```bash
sbt test # all tests
sbt "testOnly *UserServiceSpec" # single spec
sbt "testOnly -- -z 'finds user'" # by test name pattern
sbt "Test/testOptions += Tests.Argument(\"-v\")" # verbose output
```Related Skills
visual-testing
Visual Regression Testing: tool comparison (Chromatic/Percy/Playwright screenshots/BackstopJS), pixel-diff vs AI-based comparison, baseline management, flakiness strategies (masks, tolerances, waitForLoadState), CI integration with GitHub Actions, and Storybook integration.
typescript-testing
TypeScript testing patterns: Vitest for unit/integration, Playwright for E2E, MSW for API mocking, Testing Library for React components. Core TDD methodology for TypeScript/JavaScript projects.
swift-testing
Swift testing patterns: Swift Testing framework (Swift 6+), XCTest for UI tests, async/await test cases, actor testing, Combine testing, and XCUITest for UI automation. TDD for Swift/SwiftUI.
swift-protocol-di-testing
Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.
scala-patterns
Idiomatic Scala patterns: ADTs with sealed traits and case classes, typeclass pattern, Option/Either/Try error handling, for-comprehensions, Cats Effect (IO, Resource, Ref, Fiber), ZIO fundamentals, Scala 3 features (given/using, enums, extension methods, opaque types, union types). Covers both Scala 2.13 and Scala 3. Use when writing Scala, reviewing Scala code, or designing Scala domain models.
rust-testing
Rust testing patterns — unit tests with mockall, integration tests with sqlx transactions, HTTP handler testing (axum), benchmarks (criterion), property tests (proptest), fuzzing, and CI with cargo-nextest.
rust-testing-advanced
Advanced Rust testing anti-patterns and corrections — cfg(test) placement, expect() over unwrap(), mockall expectation ordering, executor mixing (#[tokio::test] vs block_on), PgPool isolation with
ruby-testing
RSpec testing patterns for Ruby and Rails — factories, mocks, request specs, feature specs, VCR, and SimpleCov coverage.
r-testing
R testing patterns: testthat 3e with expect_* assertions, snapshot testing, mocking with mockery and httptest2, covr code coverage, lintr static analysis, property-based testing with hedgehog, testing Shiny apps with shinytest2. Use when writing or reviewing R tests.
python-testing
Python testing strategies using pytest, TDD methodology, fixtures, mocking, and parametrization. Core testing fundamentals.
python-testing-advanced
Advanced Python testing — async testing with pytest-asyncio, exception/side-effect testing, test organization, common patterns (API, database, class methods), pytest configuration, and CLI reference. Extends python-testing.
php-testing
PHP testing patterns: PHPUnit 11 with mocks and data providers, Pest v3 with expectations and datasets, Laravel feature/HTTP tests with RefreshDatabase, Symfony WebTestCase, PHPStan static analysis, Infection mutation testing. Use when writing or reviewing PHP tests.