Repository: scala-steward-org/scala-steward
Pull request #1818 (2020-12-19 10:05:53)

Migrate tests to MUnit
This migrates the tests from ScalaTest to [MUnit](https://scalameta.org/munit/). The reason for this change are the diffs in case of assertion failures. It is much easier to see how large `MockState` objects differ if only their differences are reported.

Here is an example with MUnit:
```
==> X org.scalasteward.core.edit.EditAlgTest.applyUpdate with scalafmt update  0.055s munit.ComparisonFailException: /home/frank/data/code/scala-steward/core/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala:109
108:
109:    assertEquals(state, expected)
110:  }
values are not the same
=> Diff (- obtained, + expected)
     List(
-      "read",
-      "/tmp/ws/fthomas/scala-steward/.scalafmt.conf"
-    ),
-    List(
       "write",
   ),
-  uris = ...
+  uris = Map()
 )
    at munit.FunSuite.assertEquals(FunSuite.scala:11)
    at org.scalasteward.core.edit.EditAlgTest.$anonfun$new$3(EditAlgTest.scala:109)
```

And the same failure with ScalaTest:
```
[info] - applyUpdate with scalafmt update *** FAILED ***
[info]   MockState(Vector(List(test, -f, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(test, -f, /tmp/ws/fthomas/scala-steward/build.sbt), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(write, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(GIT_ASKPASS=/tmp/askpass.sh, VAR1=val1, VAR2=val2, /tmp/ws/fthomas/scala-steward, git, status, --porcelain, --untracked-files=no, --ignore-submodules), List(VAR1=val1, VAR2=val2, /tmp/ws/fthomas/scala-steward, scalafmt, --non-interactive), List(GIT_ASKPASS=/tmp/askpass.sh, VAR1=val1, VAR2=val2, /tmp/ws/fthomas/scala-steward, git, status, --porcelain, --untracked-files=no, --ignore-submodules)),Map(),Vector((None,Trying heuristic 'moduleId'), (None,Trying heuristic 'strict'), (None,Trying heuristic 'original'), (None,Trying heuristic 'relaxed'), (None,Trying heuristic 'sliding'), (None,Trying heuristic 'completeGroupId'), (None,Trying heuristic 'groupId'), (None,Trying heuristic 'specific'), (None,Executing post-update hook for org.scalameta:scalafmt-core)),Map(/tmp/ws/fthomas/scala-steward/.scalafmt.conf -> maxColumn = 100
[info]   version = 2.1.0
[info]   align.openParenCallSite = false
[info]   , /tmp/ws/fthomas/scala-steward/build.sbt -> ),Map()) was not equal to MockState(Vector(List(test, -f, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(test, -f, /tmp/ws/fthomas/scala-steward/build.sbt), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(read, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(write, /tmp/ws/fthomas/scala-steward/.scalafmt.conf), List(GIT_ASKPASS=/tmp/askpass.sh, VAR1=val1, VAR2=val2, /tmp/ws/fthomas/scala-steward, git, status, --porcelain, --untracked-files=no, --ignore-submodules), List(VAR1=val1, VAR2=val2, /tmp/ws/fthomas/scala-steward, scalafmt, --non-interactive), List(GIT_ASKPASS=/tmp/askpass.sh, VAR1=val1, VAR2=val2, /tmp/ws/fthomas/scala-steward, git, status, --porcelain, --untracked-files=no, --ignore-submodules)),Map(),Vector((None,Trying heuristic 'moduleId'), (None,Trying heuristic 'strict'), (None,Trying heuristic 'original'), (None,Trying heuristic 'relaxed'), (None,Trying heuristic 'sliding'), (None,Trying heuristic 'completeGroupId'), (None,Trying heuristic 'groupId'), (None,Trying heuristic 'specific'), (None,Executing post-update hook for org.scalameta:scalafmt-core)),Map(/tmp/ws/fthomas/scala-steward/.scalafmt.conf -> maxColumn = 100
[info]   version = 2.1.0
[info]   align.openParenCallSite = false
[info]   , /tmp/ws/fthomas/scala-steward/build.sbt -> ),Map()) (EditAlgTest.scala:69)
```

codecov[bot]: # [Codecov](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1818?src=pr&el=h1) Report
> Merging [#1818](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1818?src=pr&el=desc) (0ecf620) into [master](https://codecov.io/gh/scala-steward-org/scala-steward/commit/417f97bfd5cf893f44b0824979ba87b25f78a985?el=desc) (417f97b) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1818/graphs/tree.svg?width=650&height=150&src=pr&token=udzMsc1Dne)](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1818?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master    #1818   +/-   ##
=======================================
  Coverage   74.68%   74.68%           
=======================================
  Files         123      123           
  Lines        2074     2074           
  Branches       53       53           
=======================================
  Hits         1549     1549           
  Misses        525      525           
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1818?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1818?src=pr&el=footer). Last update [417f97b...0ecf620](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1818?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/build.sbt b/build.sbt
index b4357a82..69dcd304 100644
--- a/build.sbt
+++ b/build.sbt
@@ -99,13 +99,14 @@ lazy val core = myCrossProject("core")
       Dependencies.logbackClassic % Runtime,
       Dependencies.catsLaws % Test,
       Dependencies.circeLiteral % Test,
-      Dependencies.disciplineScalatest % Test,
+      Dependencies.disciplineMunit % Test,
       Dependencies.http4sDsl % Test,
+      Dependencies.munit % Test,
+      Dependencies.munitScalacheck % Test,
       Dependencies.refinedScalacheck % Test,
-      Dependencies.scalacheck % Test,
-      Dependencies.scalaTestFunSuite % Test,
-      Dependencies.scalaTestShouldMatcher % Test
+      Dependencies.scalacheck % Test
     ),
+    testFrameworks += new TestFramework("munit.Framework"),
     assembly / test := {},
     assemblyMergeStrategy in assembly := {
       val nativeSuffix = "\\.(?:dll|jnilib|so)$".r
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index b5ef44b8..cc32b0d8 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -21,8 +21,7 @@ object Dependencies {
   val coursierCore = "io.get-coursier" %% "coursier" % "2.0.7"
   val coursierCatsInterop = "io.get-coursier" %% "coursier-cats-interop" % coursierCore.revision
   val cron4sCore = "com.github.alonsodomin.cron4s" %% "cron4s-core" % "0.6.1"
-  val disciplineScalatest = ("org.typelevel" %% "discipline-scalatest" % "2.1.0")
-    .excludeAll(ExclusionRule().withOrganization("org.scalatest"))
+  val disciplineMunit = "org.typelevel" %% "discipline-munit" % "1.0.3"
   val fs2Core = "co.fs2" %% "fs2-core" % "2.4.6"
   val fs2Io = "co.fs2" %% "fs2-io" % fs2Core.revision
   val http4sCore = "org.http4s" %% "http4s-core" % "0.21.14"
@@ -39,6 +38,8 @@ object Dependencies {
   val millVersion = Def.setting(if (scalaBinaryVersion.value == "2.12") "0.6.3" else "0.9.3")
   val millScalalib = Def.setting("com.lihaoyi" %% "mill-scalalib" % millVersion.value)
   val monocleCore = "com.github.julien-truffaut" %% "monocle-core" % "2.1.0"
+  val munit = "org.scalameta" %% "munit" % "0.7.19"
+  val munitScalacheck = "org.scalameta" %% "munit-scalacheck" % munit.revision
   val refined = "eu.timepit" %% "refined" % "0.9.19"
   val refinedCats = "eu.timepit" %% "refined-cats" % refined.revision
   val refinedScalacheck = "eu.timepit" %% "refined-scalacheck" % refined.revision
@@ -46,7 +47,4 @@ object Dependencies {
   val scalacacheCatsEffect =
     "com.github.cb372" %% "scalacache-cats-effect" % scalacacheCaffeine.revision
   val scalacheck = "org.scalacheck" %% "scalacheck" % "1.15.2"
-  val scalaTestFunSuite = "org.scalatest" %% "scalatest-funsuite" % "3.2.3"
-  val scalaTestShouldMatcher =
-    "org.scalatest" %% "scalatest-shouldmatchers" % scalaTestFunSuite.revision
 }


Test patch:
diff --git a/modules/core/src/test/scala/org/scalasteward/core/TestInstances.scala b/modules/core/src/test/scala/org/scalasteward/core/TestInstances.scala
index 47f01743..893403da 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/TestInstances.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/TestInstances.scala
@@ -4,9 +4,11 @@ import _root_.io.chrisdavenport.log4cats.Logger
 import _root_.io.chrisdavenport.log4cats.slf4j.Slf4jLogger
 import cats.effect.{ContextShift, IO, Timer}
 import org.scalacheck.{Arbitrary, Cogen, Gen}
-import org.scalasteward.core.data.{Resolver, Scope, Version}
-import org.scalasteward.core.util.Change
+import org.scalasteward.core.TestSyntax._
+import org.scalasteward.core.data.Update.Single
+import org.scalasteward.core.data.{Resolver, Scope, Update, Version}
 import org.scalasteward.core.util.Change.{Changed, Unchanged}
+import org.scalasteward.core.util.{Change, Nel}
 import scala.concurrent.ExecutionContext
 
 object TestInstances {
@@ -32,6 +34,16 @@ object TestInstances {
   implicit def scopeCogen[T](implicit cogenT: Cogen[T]): Cogen[Scope[T]] =
     cogenT.contramap(_.value)
 
+  implicit val updateArbitrary: Arbitrary[Update] =
+    Arbitrary(
+      for {
+        groupId <- Gen.alphaStr
+        artifactId <- Gen.alphaStr
+        currentVersion <- Gen.alphaStr
+        newerVersion <- Gen.alphaStr
+      } yield Single(groupId % artifactId % currentVersion, Nel.one(newerVersion))
+    )
+
   private val hashGen: Gen[String] =
     for {
       sep <- Gen.oneOf('-', '+')
diff --git a/modules/core/src/test/scala/org/scalasteward/core/application/CliTest.scala b/modules/core/src/test/scala/org/scalasteward/core/application/CliTest.scala
index bfcf0738..d96b9a00 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/application/CliTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/application/CliTest.scala
@@ -1,18 +1,15 @@
 package org.scalasteward.core.application
 
 import better.files.File
+import munit.FunSuite
 import org.http4s.syntax.literals._
 import org.scalasteward.core.application.Cli.EnvVar
 import org.scalasteward.core.application.Cli.ParseResult._
-import org.scalatest.EitherValues
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-
 import scala.concurrent.duration._
 
-class CliTest extends AnyFunSuite with Matchers with EitherValues {
+class CliTest extends FunSuite {
   test("parseArgs: example") {
-    Cli.parseArgs(
+    val obtained = Cli.parseArgs(
       List(
         List("--workspace", "a"),
         List("--repos-file", "b"),
@@ -31,7 +28,8 @@ class CliTest extends AnyFunSuite with Matchers with EitherValues {
         List("--github-app-id", "12345678"),
         List("--github-app-key-file", "example_app_key")
       ).flatten
-    ) shouldBe Success(
+    )
+    val expected = Success(
       Cli.Args(
         workspace = File("a"),
         reposFile = File("b"),
@@ -50,10 +48,11 @@ class CliTest extends AnyFunSuite with Matchers with EitherValues {
         githubAppKeyFile = Some(File("example_app_key"))
       )
     )
+    assertEquals(obtained, expected)
   }
 
   test("parseArgs: minimal example") {
-    Cli.parseArgs(
+    val obtained = Cli.parseArgs(
       List(
         List("--workspace", "a"),
         List("--repos-file", "b"),
@@ -61,7 +60,8 @@ class CliTest extends AnyFunSuite with Matchers with EitherValues {
         List("--vcs-login", "e"),
         List("--git-ask-pass", "f")
       ).flatten
-    ) shouldBe Success(
+    )
+    val expected = Success(
       Cli.Args(
         workspace = File("a"),
         reposFile = File("b"),
@@ -70,54 +70,57 @@ class CliTest extends AnyFunSuite with Matchers with EitherValues {
         gitAskPass = File("f")
       )
     )
+    assertEquals(obtained, expected)
   }
 
   test("parseArgs: fail if required option not provided") {
-    Cli.parseArgs(Nil).asInstanceOf[Error].error should startWith("Required option")
+    assert(clue(Cli.parseArgs(Nil).asInstanceOf[Error].error).startsWith("Required option"))
   }
 
   test("parseArgs: unrecognized argument") {
-    Cli.parseArgs(List("--foo")).asInstanceOf[Error].error should startWith("Unrecognized")
+    assert(clue(Cli.parseArgs(List("--foo")).asInstanceOf[Error].error).startsWith("Unrecognized"))
   }
 
   test("parseArgs: --help") {
-    Cli.parseArgs(List("--help")).asInstanceOf[Help].help should include("--git-author-email")
+    assert(
+      clue(Cli.parseArgs(List("--help")).asInstanceOf[Help].help).contains("--git-author-email")
+    )
   }
 
   test("parseArgs: --usage") {
-    Cli.parseArgs(List("--usage")).asInstanceOf[Help].help should startWith("Usage: args")
+    assert(clue(Cli.parseArgs(List("--usage")).asInstanceOf[Help].help).startsWith("Usage: args"))
   }
 
   test("envVarArgParser: env-var without equals sign") {
-    Cli.envVarArgParser(None, "SBT_OPTS").isLeft shouldBe true
+    assert(clue(Cli.envVarArgParser(None, "SBT_OPTS")).isLeft)
   }
 
   test("envVarArgParser: env-var with multiple equals signs") {
     val value = "-Xss8m -XX:MaxMetaspaceSize=256m"
-    Cli.envVarArgParser(None, s"SBT_OPTS=$value") shouldBe Right(EnvVar("SBT_OPTS", value))
+    assertEquals(Cli.envVarArgParser(None, s"SBT_OPTS=$value"), Right(EnvVar("SBT_OPTS", value)))
   }
 
   test("finiteDurationArgParser: well-formed duration") {
-    Cli.finiteDurationArgParser(None, "30min") shouldBe Right(30.minutes)
+    assertEquals(Cli.finiteDurationArgParser(None, "30min"), Right(30.minutes))
   }
 
   test("finiteDurationArgParser: malformed duration") {
-    Cli.finiteDurationArgParser(None, "xyz").isLeft shouldBe true
+    assert(clue(Cli.finiteDurationArgParser(None, "xyz")).isLeft)
   }
 
   test("finiteDurationArgParser: malformed duration (Inf)") {
-    Cli.finiteDurationArgParser(None, "Inf").isLeft shouldBe true
+    assert(clue(Cli.finiteDurationArgParser(None, "Inf")).isLeft)
   }
 
   test("finiteDurationArgParser: previous value") {
-    Cli.finiteDurationArgParser(Some(10.seconds), "20seconds").isLeft shouldBe true
+    assert(clue(Cli.finiteDurationArgParser(Some(10.seconds), "20seconds")).isLeft)
   }
 
   test("fileArgParser: previous value") {
-    Cli.fileArgParser(Some(File("/tmp")), "/opt").isLeft shouldBe true
+    assert(clue(Cli.fileArgParser(Some(File("/tmp")), "/opt")).isLeft)
   }
 
   test("supportedVCSArgParser: unknown value") {
-    Cli.supportedVCSArgParser(None, "sourceforge").isLeft shouldBe true
+    assert(clue(Cli.supportedVCSArgParser(None, "sourceforge")).isLeft)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/BuildToolDispatcherTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/BuildToolDispatcherTest.scala
index 49cd62e3..a803f815 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/BuildToolDispatcherTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/BuildToolDispatcherTest.scala
@@ -1,5 +1,6 @@
 package org.scalasteward.core.buildtool
 
+import munit.FunSuite
 import org.scalasteward.core.buildtool.sbt.command._
 import org.scalasteward.core.buildtool.sbt.data.SbtVersion
 import org.scalasteward.core.data.{Resolver, Scope, Version}
@@ -7,10 +8,8 @@ import org.scalasteward.core.mock.MockContext.{buildToolDispatcher, config}
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.scalafmt
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class BuildToolDispatcherTest extends AnyFunSuite with Matchers {
+class BuildToolDispatcherTest extends FunSuite {
   test("getDependencies") {
     val repo = Repo("typelevel", "cats")
     val repoDir = config.workspace / repo.show
@@ -21,7 +20,7 @@ class BuildToolDispatcherTest extends AnyFunSuite with Matchers {
     val initial = MockState.empty.copy(files = files)
     val (state, deps) = buildToolDispatcher.getDependencies(repo).run(initial).unsafeRunSync()
 
-    state shouldBe initial.copy(commands =
+    val expectedState = initial.copy(commands =
       Vector(
         List("test", "-f", s"$repoDir/pom.xml"),
         List("test", "-f", s"$repoDir/build.sc"),
@@ -43,7 +42,9 @@ class BuildToolDispatcherTest extends AnyFunSuite with Matchers {
         List("read", s"$repoDir/.scalafmt.conf")
       )
     )
-    deps shouldBe List(
+    assertEquals(state, expectedState)
+
+    val expectedDeps = List(
       Scope(
         List(
           sbt.sbtDependency(SbtVersion("1.2.6")).get,
@@ -52,5 +53,6 @@ class BuildToolDispatcherTest extends AnyFunSuite with Matchers {
         List(Resolver.mavenCentral)
       )
     )
+    assertEquals(deps, expectedDeps)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/maven/MavenAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/maven/MavenAlgTest.scala
index 61ab9f17..1beb25ae 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/maven/MavenAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/maven/MavenAlgTest.scala
@@ -1,13 +1,12 @@
 package org.scalasteward.core.buildtool.maven
 
 import better.files.File
+import munit.FunSuite
 import org.scalasteward.core.mock.MockContext._
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class MavenAlgTest extends AnyFunSuite with Matchers {
+class MavenAlgTest extends FunSuite {
   test("getDependencies") {
     val repo = Repo("namespace", "repo-name")
     val repoDir = config.workspace / repo.show
@@ -16,7 +15,7 @@ class MavenAlgTest extends AnyFunSuite with Matchers {
     val state =
       mavenAlg.getDependencies(repo).runS(MockState.empty.copy(files = files)).unsafeRunSync()
 
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       files = files,
       logs = Vector.empty,
       commands = Vector(
@@ -44,5 +43,7 @@ class MavenAlgTest extends AnyFunSuite with Matchers {
         )
       )
     )
+
+    assertEquals(state, expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/maven/parserTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/maven/parserTest.scala
index 4ef036bd..9635c289 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/maven/parserTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/maven/parserTest.scala
@@ -1,12 +1,11 @@
 package org.scalasteward.core.buildtool.maven
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.ArtifactId
 import org.scalasteward.core.data.Resolver.MavenRepository
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class parserTest extends AnyFunSuite with Matchers {
+class parserTest extends FunSuite {
   test("parseDependencies") {
     val input =
       """|[INFO] Scanning for projects...
@@ -31,12 +30,13 @@ class parserTest extends AnyFunSuite with Matchers {
          |[INFO] ------------------------------------------------------------------------
          |""".stripMargin.linesIterator.toList
     val dependencies = parser.parseDependencies(input)
-    dependencies shouldBe List(
+    val expected = List(
       "org.typelevel" % ArtifactId("cats-core", "cats-core_2.12") % "1.5.0",
       "org.hamcrest" % "hamcrest-core" % "1.3" % "test",
       "junit" % "junit" % "4.12" % "test",
       "ch.qos.logback" % "logback-core" % "1.1.11"
     )
+    assertEquals(dependencies, expected)
   }
 
   test("parseResolvers") {
@@ -60,7 +60,7 @@ class parserTest extends AnyFunSuite with Matchers {
          | releases: [enabled => false, update => daily]
          |""".stripMargin.linesIterator.toList
     val resolvers = parser.parseResolvers(input)
-    resolvers shouldBe List(
+    val expected = List(
       MavenRepository(
         "sonatype-nexus-snapshots",
         "https://oss.sonatype.org/content/repositories/snapshots",
@@ -69,5 +69,6 @@ class parserTest extends AnyFunSuite with Matchers {
       MavenRepository("bintrayakkamaven", "https://dl.bintray.com/akka/maven/", None),
       MavenRepository("apache.snapshots", "http://repository.apache.org/snapshots", None)
     )
+    assertEquals(resolvers, expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/mill/MillAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/mill/MillAlgTest.scala
index a68fd183..2d7c865b 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/mill/MillAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/mill/MillAlgTest.scala
@@ -1,13 +1,12 @@
 package org.scalasteward.core.buildtool.mill
 
+import munit.FunSuite
 import org.scalasteward.core.buildtool.mill.MillAlg.extractDeps
 import org.scalasteward.core.mock.MockContext.{config, millAlg}
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class MillAlgTest extends AnyFunSuite with Matchers {
+class MillAlgTest extends FunSuite {
   test("getDependencies") {
     val repo = Repo("lihaoyi", "fastparse")
     val repoDir = config.workspace / repo.show
@@ -27,12 +26,13 @@ class MillAlgTest extends AnyFunSuite with Matchers {
     )
     val initial = MockState.empty.copy(commandOutputs = Map(millCmd -> List("""{"modules":[]}""")))
     val state = millAlg.getDependencies(repo).runS(initial).unsafeRunSync()
-    state shouldBe initial.copy(
+    val expected = initial.copy(
       commands = Vector(
         List("write", predef),
         repoDir.toString :: millCmd,
         List("rm", "-rf", predef)
       )
     )
+    assertEquals(state, expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/mill/MillDepParserTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/mill/MillDepParserTest.scala
index 6512ada2..2a98b86c 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/mill/MillDepParserTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/mill/MillDepParserTest.scala
@@ -1,10 +1,9 @@
 package org.scalasteward.core.buildtool.mill
 
+import munit.FunSuite
 import org.scalasteward.core.data.{ArtifactId, Dependency, GroupId}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class MillDepParserTest extends AnyFunSuite with Matchers {
+class MillDepParserTest extends FunSuite {
   test("parse dependencies from https://github.com/lihaoyi/requests-scala") {
     val data =
       """{
@@ -128,18 +127,18 @@ class MillDepParserTest extends AnyFunSuite with Matchers {
         |  ]
         |}
         |""".stripMargin
-    val result = parser.parseModules(data).fold(fail(_), identity)
+    val Right(result) = parser.parseModules(data)
 
     val dep12 = List(
       Dependency(GroupId("com.lihaoyi"), ArtifactId("geny", Some("geny_2.12")), "0.6.0")
     )
 
-    assert(result.headOption.map(_.dependencies) === Some(dep12))
+    assertEquals(result.headOption.map(_.dependencies), Some(dep12))
 
     val dep13 = List(
       Dependency(GroupId("com.lihaoyi"), ArtifactId("geny", Some("geny_2.13")), "0.6.0")
     )
 
-    assert(result.find(_.name == "requests[2.13.0]").map(_.dependencies) === Some(dep13))
+    assertEquals(result.find(_.name == "requests[2.13.0]").map(_.dependencies), Some(dep13))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala
index ff2fd60b..1d762fd1 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala
@@ -1,6 +1,7 @@
 package org.scalasteward.core.buildtool.sbt
 
 import cats.data.StateT
+import munit.FunSuite
 import org.scalasteward.core.buildtool.sbt.command._
 import org.scalasteward.core.data.{GroupId, Version}
 import org.scalasteward.core.mock.MockContext._
@@ -8,15 +9,14 @@ import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.scalafix.Migration
 import org.scalasteward.core.util.Nel
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class SbtAlgTest extends AnyFunSuite with Matchers {
+class SbtAlgTest extends FunSuite {
   test("addGlobalPlugins") {
-    sbtAlg
+    val obtained = sbtAlg
       .addGlobalPlugins(StateT.modify(_.exec(List("fa"))))
       .runS(MockState.empty)
-      .unsafeRunSync() shouldBe MockState.empty.copy(
+      .unsafeRunSync()
+    val expected = MockState.empty.copy(
       commands = Vector(
         List("read", "classpath:org/scalasteward/sbt/plugin/StewardPlugin.scala"),
         List("write", "/tmp/steward/.sbt/0.13/plugins/StewardPlugin.scala"),
@@ -28,6 +28,7 @@ class SbtAlgTest extends AnyFunSuite with Matchers {
       logs = Vector((None, "Add global sbt plugins")),
       files = Map.empty
     )
+    assertEquals(obtained, expected)
   }
 
   test("getDependencies") {
@@ -36,7 +37,7 @@ class SbtAlgTest extends AnyFunSuite with Matchers {
     val files = Map(repoDir / "project" / "build.properties" -> "sbt.version=1.2.6")
     val initial = MockState.empty.copy(files = files)
     val state = sbtAlg.getDependencies(repo).runS(initial).unsafeRunSync()
-    state shouldBe initial.copy(
+    val expected = initial.copy(
       commands = Vector(
         List(
           repoDir.toString,
@@ -54,6 +55,7 @@ class SbtAlgTest extends AnyFunSuite with Matchers {
         List("read", s"$repoDir/project/build.properties")
       )
     )
+    assertEquals(state, expected)
   }
 
   test("runMigrations") {
@@ -70,8 +72,7 @@ class SbtAlgTest extends AnyFunSuite with Matchers {
       )
     )
     val state = sbtAlg.runMigrations(repo, migrations).runS(MockState.empty).unsafeRunSync()
-
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List("write", "/tmp/steward/.sbt/0.13/plugins/scala-steward-scalafix.sbt"),
         List("write", "/tmp/steward/.sbt/1.0/plugins/scala-steward-scalafix.sbt"),
@@ -92,6 +93,7 @@ class SbtAlgTest extends AnyFunSuite with Matchers {
         List("rm", "-rf", "/tmp/steward/.sbt/0.13/plugins/scala-steward-scalafix.sbt")
       )
     )
+    assertEquals(state, expected)
   }
 
   test("runMigrations: migration with scalacOptions") {
@@ -108,8 +110,7 @@ class SbtAlgTest extends AnyFunSuite with Matchers {
       )
     )
     val state = sbtAlg.runMigrations(repo, migrations).runS(MockState.empty).unsafeRunSync()
-
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List("write", "/tmp/steward/.sbt/0.13/plugins/scala-steward-scalafix.sbt"),
         List("write", "/tmp/steward/.sbt/1.0/plugins/scala-steward-scalafix.sbt"),
@@ -132,5 +133,6 @@ class SbtAlgTest extends AnyFunSuite with Matchers {
         List("rm", "-rf", "/tmp/steward/.sbt/0.13/plugins/scala-steward-scalafix.sbt")
       )
     )
+    assertEquals(state, expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/parserTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/parserTest.scala
index ee87f587..5f39432f 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/parserTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/parserTest.scala
@@ -1,16 +1,15 @@
 package org.scalasteward.core.buildtool.sbt
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.buildtool.sbt.data.SbtVersion
 import org.scalasteward.core.buildtool.sbt.parser._
 import org.scalasteward.core.data.Resolver.{Credentials, IvyRepository, MavenRepository}
 import org.scalasteward.core.data.{ArtifactId, Scope}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class parserTest extends AnyFunSuite with Matchers {
+class parserTest extends FunSuite {
   test("parseBuildProperties: with whitespace") {
-    parseBuildProperties("sbt.version = 1.2.8") shouldBe Some(SbtVersion("1.2.8"))
+    assertEquals(parseBuildProperties("sbt.version = 1.2.8"), Some(SbtVersion("1.2.8")))
   }
 
   test("parseDependencies") {
@@ -33,7 +32,7 @@ class parserTest extends AnyFunSuite with Matchers {
          |[info] --- snip ---
          |""".stripMargin.linesIterator.toList
     val scopes = parseDependencies(lines)
-    scopes shouldBe List(
+    val expected = List(
       Scope(
         List(
           "org.scala-lang" % "scala-library" % "2.12.7",
@@ -71,5 +70,6 @@ class parserTest extends AnyFunSuite with Matchers {
         )
       )
     )
+    assertEquals(scopes, expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/sbtTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/sbtTest.scala
index d11ffbf2..198e7009 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/sbtTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/sbtTest.scala
@@ -1,11 +1,12 @@
 package org.scalasteward.core.buildtool.sbt
 
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
+import munit.FunSuite
 
-class sbtTest extends AnyFunSuite with Matchers {
+class sbtTest extends FunSuite {
   test("scalaStewardScalafixOptions") {
-    scalaStewardScalafixOptions(List("-P:semanticdb:synthetics:on")).content shouldBe
+    assertEquals(
+      scalaStewardScalafixOptions(List("-P:semanticdb:synthetics:on")).content,
       """ThisBuild / scalacOptions ++= List("-P:semanticdb:synthetics:on")"""
+    )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/coursier/CoursierAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/coursier/CoursierAlgTest.scala
index 4361b851..c6232133 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/coursier/CoursierAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/coursier/CoursierAlgTest.scala
@@ -1,15 +1,14 @@
 package org.scalasteward.core.coursier
 
+import munit.FunSuite
 import org.http4s.syntax.literals._
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.buildtool.sbt.data.{SbtVersion, ScalaVersion}
 import org.scalasteward.core.data.{ArtifactId, Dependency, GroupId}
 import org.scalasteward.core.mock.MockContext._
 import org.scalasteward.core.mock.MockState
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class CoursierAlgTest extends AnyFunSuite with Matchers {
+class CoursierAlgTest extends FunSuite {
   test("getArtifactUrl: library") {
     val dep =
       Dependency(GroupId("org.typelevel"), ArtifactId("cats-effect", "cats-effect_2.12"), "1.0.0")
@@ -17,8 +16,8 @@ class CoursierAlgTest extends AnyFunSuite with Matchers {
       .getArtifactUrl(dep.withMavenCentral)
       .run(MockState.empty)
       .unsafeRunSync()
-    state shouldBe MockState.empty
-    result shouldBe Some(uri"https://github.com/typelevel/cats-effect")
+    assertEquals(state, MockState.empty)
+    assertEquals(result, Some(uri"https://github.com/typelevel/cats-effect"))
   }
 
   test("getArtifactUrl: defaults to homepage") {
@@ -31,8 +30,8 @@ class CoursierAlgTest extends AnyFunSuite with Matchers {
       .getArtifactUrl(dep.withMavenCentral)
       .run(MockState.empty)
       .unsafeRunSync()
-    state shouldBe MockState.empty
-    result shouldBe Some(uri"https://github.com/playframework/play-ws")
+    assertEquals(state, MockState.empty)
+    assertEquals(result, Some(uri"https://github.com/playframework/play-ws"))
   }
 
   test("getArtifactUrl: URL with no or invalid scheme 1") {
@@ -45,8 +44,8 @@ class CoursierAlgTest extends AnyFunSuite with Matchers {
       .getArtifactUrl(dep.withMavenCentral)
       .run(MockState.empty)
       .unsafeRunSync()
-    state shouldBe MockState.empty
-    result shouldBe Some(uri"http://msgpack.org/")
+    assertEquals(state, MockState.empty)
+    assertEquals(result, Some(uri"http://msgpack.org/"))
   }
 
   test("getArtifactUrl: URL with no or invalid scheme 2") {
@@ -59,8 +58,8 @@ class CoursierAlgTest extends AnyFunSuite with Matchers {
       .getArtifactUrl(dep.withMavenCentral)
       .run(MockState.empty)
       .unsafeRunSync()
-    state shouldBe MockState.empty
-    result shouldBe Some(uri"http://code.google.com/p/flying-saucer/")
+    assertEquals(state, MockState.empty)
+    assertEquals(result, Some(uri"http://code.google.com/p/flying-saucer/"))
   }
 
   test("getArtifactUrl: from parent") {
@@ -73,8 +72,8 @@ class CoursierAlgTest extends AnyFunSuite with Matchers {
       .getArtifactUrl(dep.withMavenCentral)
       .run(MockState.empty)
       .unsafeRunSync()
-    state shouldBe MockState.empty
-    result shouldBe Some(uri"https://bytebuddy.net")
+    assertEquals(state, MockState.empty)
+    assertEquals(result, Some(uri"https://bytebuddy.net"))
   }
 
   test("getArtifactUrl: minimal pom") {
@@ -87,8 +86,8 @@ class CoursierAlgTest extends AnyFunSuite with Matchers {
       .getArtifactUrl(dep.withMavenCentral)
       .run(MockState.empty)
       .unsafeRunSync()
-    state shouldBe MockState.empty
-    result shouldBe None
+    assertEquals(state, MockState.empty)
+    assertEquals(result, None)
   }
 
   test("getArtifactUrl: sbt plugin on Maven Central") {
@@ -103,8 +102,8 @@ class CoursierAlgTest extends AnyFunSuite with Matchers {
       .getArtifactUrl(dep.withMavenCentral)
       .run(MockState.empty)
       .unsafeRunSync()
-    state shouldBe MockState.empty
-    result shouldBe Some(uri"https://github.com/xerial/sbt-sonatype")
+    assertEquals(state, MockState.empty)
+    assertEquals(result, Some(uri"https://github.com/xerial/sbt-sonatype"))
   }
 
   test("getArtifactUrl: sbt plugin on sbt-plugin-releases") {
@@ -117,8 +116,8 @@ class CoursierAlgTest extends AnyFunSuite with Matchers {
     )
     val (state, result) =
       coursierAlg.getArtifactUrl(dep.withSbtPluginReleases).run(MockState.empty).unsafeRunSync()
-    state shouldBe MockState.empty
-    result shouldBe Some(uri"https://github.com/sbt/sbt-release")
+    assertEquals(state, MockState.empty)
+    assertEquals(result, Some(uri"https://github.com/sbt/sbt-release"))
   }
 
   test("getArtifactIdUrlMapping") {
@@ -130,10 +129,13 @@ class CoursierAlgTest extends AnyFunSuite with Matchers {
       .getArtifactIdUrlMapping(dependencies.withMavenCentral)
       .run(MockState.empty)
       .unsafeRunSync()
-    state shouldBe MockState.empty
-    result shouldBe Map(
-      "cats-core" -> uri"https://github.com/typelevel/cats",
-      "cats-effect" -> uri"https://github.com/typelevel/cats-effect"
+    assertEquals(state, MockState.empty)
+    assertEquals(
+      result,
+      Map(
+        "cats-core" -> uri"https://github.com/typelevel/cats",
+        "cats-effect" -> uri"https://github.com/typelevel/cats-effect"
+      )
     )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/data/ScopeTest.scala b/modules/core/src/test/scala/org/scalasteward/core/data/ScopeTest.scala
index a432fe34..941c8777 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/data/ScopeTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/data/ScopeTest.scala
@@ -1,12 +1,11 @@
 package org.scalasteward.core.data
+
 import cats.kernel.laws.discipline.OrderTests
 import cats.laws.discipline.TraverseTests
+import munit.DisciplineSuite
 import org.scalasteward.core.TestInstances._
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-import org.typelevel.discipline.scalatest.FunSuiteDiscipline
 
-class ScopeTest extends AnyFunSuite with FunSuiteDiscipline with ScalaCheckPropertyChecks {
+class ScopeTest extends DisciplineSuite {
   checkAll("Traverse[Scope]", TraverseTests[Scope].traverse[Int, Int, Int, Int, Option, Option])
 
   checkAll("Order[Scope[Int]]", OrderTests[Scope[Int]].order)
diff --git a/modules/core/src/test/scala/org/scalasteward/core/data/SemVerTest.scala b/modules/core/src/test/scala/org/scalasteward/core/data/SemVerTest.scala
index d0599610..0bf05339 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/data/SemVerTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/data/SemVerTest.scala
@@ -2,11 +2,10 @@ package org.scalasteward.core.data
 
 import eu.timepit.refined.types.numeric.NonNegBigInt
 import eu.timepit.refined.types.string.NonEmptyString
+import munit.FunSuite
 import org.scalasteward.core.data.SemVer.Change
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class SemVerTest extends AnyFunSuite with Matchers {
+class SemVerTest extends FunSuite {
   implicit val toNonNegBigInt: Int => NonNegBigInt =
     i => NonNegBigInt.unsafeFrom(BigInt(i))
 
@@ -14,64 +13,81 @@ class SemVerTest extends AnyFunSuite with Matchers {
     NonEmptyString.unsafeFrom
 
   test("parse: simple examples") {
-    SemVer.parse("1.2.3") shouldBe Some(SemVer(1, 2, 3, None, None))
-    SemVer.parse("0.0.0") shouldBe Some(SemVer(0, 0, 0, None, None))
-    SemVer.parse("123.456.789") shouldBe Some(SemVer(123, 456, 789, None, None))
+    assertEquals(SemVer.parse("1.2.3"), Some(SemVer(1, 2, 3, None, None)))
+    assertEquals(SemVer.parse("0.0.0"), Some(SemVer(0, 0, 0, None, None)))
+    assertEquals(SemVer.parse("123.456.789"), Some(SemVer(123, 456, 789, None, None)))
   }
 
   test("parse: with pre-release identifier") {
-    SemVer.parse("1.0.0-SNAP5") shouldBe Some(SemVer(1, 0, 0, Some("SNAP5"), None))
-    SemVer.parse("9.10.100-0.3.7") shouldBe Some(SemVer(9, 10, 100, Some("0.3.7"), None))
+    assertEquals(SemVer.parse("1.0.0-SNAP5"), Some(SemVer(1, 0, 0, Some("SNAP5"), None)))
+    assertEquals(SemVer.parse("9.10.100-0.3.7"), Some(SemVer(9, 10, 100, Some("0.3.7"), None)))
   }
 
   test("parse: empty pre-release identifier") {
-    SemVer.parse("5.6.7-") shouldBe None
+    assertEquals(SemVer.parse("5.6.7-"), None)
   }
 
   test("parse: with build metadata") {
-    SemVer.parse("1.0.0+20130313144700") shouldBe
+    assertEquals(
+      SemVer.parse("1.0.0+20130313144700"),
       Some(SemVer(1, 0, 0, None, Some("20130313144700")))
-    SemVer.parse("1.0.0-beta+exp.sha.5114f85") shouldBe
+    )
+    assertEquals(
+      SemVer.parse("1.0.0-beta+exp.sha.5114f85"),
       Some(SemVer(1, 0, 0, Some("beta"), Some("exp.sha.5114f85")))
+    )
   }
 
   test("parse: empty build metadata") {
-    SemVer.parse("6.7.8+") shouldBe None
-    SemVer.parse("9.10.11-M1+") shouldBe None
+    assertEquals(SemVer.parse("6.7.8+"), None)
+    assertEquals(SemVer.parse("9.10.11-M1+"), None)
   }
 
   test("parse: negative numbers") {
-    SemVer.parse("-1.0.0") shouldBe None
-    SemVer.parse("0.-1.0") shouldBe None
-    SemVer.parse("0.0.-1") shouldBe None
+    assertEquals(SemVer.parse("-1.0.0"), None)
+    assertEquals(SemVer.parse("0.-1.0"), None)
+    assertEquals(SemVer.parse("0.0.-1"), None)
   }
 
   test("parse: leading zeros") {
-    SemVer.parse("01.0.0") shouldBe None
-    SemVer.parse("0.01.0") shouldBe None
-    SemVer.parse("0.0.01") shouldBe None
+    assertEquals(SemVer.parse("01.0.0"), None)
+    assertEquals(SemVer.parse("0.01.0"), None)
+    assertEquals(SemVer.parse("0.0.01"), None)
   }
 
   test("getChange") {
-    SemVer.getChange(SemVer(1, 3, 4, None, None), SemVer(2, 1, 2, None, None)) shouldBe
+    assertEquals(
+      SemVer.getChange(SemVer(1, 3, 4, None, None), SemVer(2, 1, 2, None, None)),
       Some(Change.Major)
-    SemVer.getChange(SemVer(2, 3, 4, None, None), SemVer(2, 5, 2, None, None)) shouldBe
+    )
+    assertEquals(
+      SemVer.getChange(SemVer(2, 3, 4, None, None), SemVer(2, 5, 2, None, None)),
       Some(Change.Minor)
-    SemVer.getChange(
-      SemVer(2, 3, 4, Some("SNAP1"), None),
-      SemVer(2, 3, 4, Some("SNAP2"), None)
-    ) shouldBe
+    )
+    assertEquals(
+      SemVer.getChange(
+        SemVer(2, 3, 4, Some("SNAP1"), None),
+        SemVer(2, 3, 4, Some("SNAP2"), None)
+      ),
       Some(Change.PreRelease)
-    SemVer.getChange(
-      SemVer(2, 3, 4, Some("M1"), Some("1")),
-      SemVer(2, 3, 4, Some("M1"), Some("2"))
-    ) shouldBe
+    )
+    assertEquals(
+      SemVer.getChange(
+        SemVer(2, 3, 4, Some("M1"), Some("1")),
+        SemVer(2, 3, 4, Some("M1"), Some("2"))
+      ),
       Some(Change.BuildMetadata)
-    SemVer.getChange(
-      SemVer(2, 3, 4, Some("M1"), None),
-      SemVer(2, 3, 4, Some("M1"), None)
-    ) shouldBe None
-    SemVer.getChange(SemVer(0, 20, 0, Some("M4"), None), SemVer(0, 20, 3, None, None)) shouldBe
+    )
+    assertEquals(
+      SemVer.getChange(
+        SemVer(2, 3, 4, Some("M1"), None),
+        SemVer(2, 3, 4, Some("M1"), None)
+      ),
+      None
+    )
+    assertEquals(
+      SemVer.getChange(SemVer(0, 20, 0, Some("M4"), None), SemVer(0, 20, 3, None, None)),
       Some(Change.PreRelease)
+    )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/data/UpdateTest.scala b/modules/core/src/test/scala/org/scalasteward/core/data/UpdateTest.scala
index dacf8caf..4360e353 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/data/UpdateTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/data/UpdateTest.scala
@@ -1,37 +1,38 @@
 package org.scalasteward.core.data
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.Update.{Group, Single}
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class UpdateTest extends AnyFunSuite with Matchers {
+class UpdateTest extends FunSuite {
   test("Group.mainArtifactId") {
-    Group(
+    val update = Group(
       "org.http4s" %
         Nel.of("http4s-blaze-server", "http4s-circe", "http4s-core", "http4s-dsl") % "0.18.16",
       Nel.of("0.18.18")
-    ).mainArtifactId shouldBe "http4s-core"
+    )
+    assertEquals(update.mainArtifactId, "http4s-core")
   }
 
   test("Group.mainArtifactId: artifactIds contains a common suffix") {
     val update =
       Group("com.softwaremill.sttp" % Nel.of("circe", "core", "monix") % "1.3.2", Nel.of("1.3.3"))
-    update.mainArtifactId shouldBe "circe"
+    assertEquals(update.mainArtifactId, "circe")
   }
 
   test("groupByGroupId: 1 update") {
     val updates = List(Single("org.specs2" % "specs2-core" % "3.9.4", Nel.of("3.9.5")))
-    Update.groupByGroupId(updates) shouldBe updates
+    assertEquals(Update.groupByGroupId(updates), updates)
   }
 
   test("groupByGroupId: 2 updates") {
     val update0 = Single("org.specs2" % "specs2-core" % "3.9.4", Nel.of("3.9.5"))
     val update1 = Single("org.specs2" % "specs2-scalacheck" % "3.9.4", Nel.of("3.9.5"))
-    Update.groupByGroupId(List(update0, update1)) shouldBe List(
+    val expected = List(
       Group("org.specs2" % Nel.of("specs2-core", "specs2-scalacheck") % "3.9.4", Nel.of("3.9.5"))
     )
+    assertEquals(Update.groupByGroupId(List(update0, update1)), expected)
   }
 
   test("groupByArtifactIdName: 2 updates") {
@@ -43,19 +44,20 @@ class UpdateTest extends AnyFunSuite with Matchers {
       "org.specs2" % ArtifactId("specs2-core", "specs2-core_2.13") % "3.9.4" % "test",
       Nel.of("3.9.5")
     )
-    Update.groupByArtifactIdName(List(update0, update1)) shouldBe List(
+    val expected = List(
       Single(
         update0.crossDependency.dependencies ::: update1.crossDependency.dependencies,
         Nel.of("3.9.5")
       )
     )
+    assertEquals(Update.groupByArtifactIdName(List(update0, update1)), expected)
   }
 
   test("groupByArtifactIdName: 3 updates ") {
     val update0 = Single("org.specs2" % "specs2-core" % "3.9.4", Nel.of("3.9.5"))
     val update1 = Single("org.specs2" % "specs2-core" % "3.9.4" % "test", Nel.of("3.9.5"))
     val update2 = Single("org.specs2" % "specs2-scalacheck" % "3.9.4", Nel.of("3.9.5"))
-    Update.groupByArtifactIdName(List(update0, update1, update2)) shouldBe List(
+    val expected = List(
       Single(
         Nel.of(
           "org.specs2" % "specs2-core" % "3.9.4",
@@ -65,16 +67,17 @@ class UpdateTest extends AnyFunSuite with Matchers {
       ),
       update2
     )
+    assertEquals(Update.groupByArtifactIdName(List(update0, update1, update2)), expected)
   }
 
   test("Single.show") {
     val update = Single("org.specs2" % "specs2-core" % "3.9.4" % "test", Nel.of("3.9.5"))
-    update.show shouldBe "org.specs2:specs2-core : 3.9.4 -> 3.9.5"
+    assertEquals(update.show, "org.specs2:specs2-core : 3.9.4 -> 3.9.5")
   }
 
   test("Group.show") {
     val update =
       Group("org.scala-sbt" % Nel.of("sbt-launch", "scripted-plugin") % "1.2.1", Nel.of("1.2.4"))
-    update.show shouldBe "org.scala-sbt:{sbt-launch, scripted-plugin} : 1.2.1 -> 1.2.4"
+    assertEquals(update.show, "org.scala-sbt:{sbt-launch, scripted-plugin} : 1.2.1 -> 1.2.4")
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/data/VersionTest.scala b/modules/core/src/test/scala/org/scalasteward/core/data/VersionTest.scala
index a8302019..8e2cc745 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/data/VersionTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/data/VersionTest.scala
@@ -2,24 +2,18 @@ package org.scalasteward.core.data
 
 import cats.implicits._
 import cats.kernel.laws.discipline.OrderTests
+import munit.DisciplineSuite
+import org.scalacheck.Prop._
 import org.scalasteward.core.TestInstances._
 import org.scalasteward.core.data.Version.Component
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-import org.typelevel.discipline.scalatest.FunSuiteDiscipline
 import scala.util.Random
 
-class VersionTest
-    extends AnyFunSuite
-    with FunSuiteDiscipline
-    with Matchers
-    with ScalaCheckPropertyChecks {
+class VersionTest extends DisciplineSuite {
   checkAll("Order[Version]", OrderTests[Version].order)
 
   test("issue 1615: broken transitivity") {
     val res = OrderTests[Version].laws.transitivity(Version(""), Version("0"), Version("X"))
-    res.lhs shouldBe res.rhs
+    assertEquals(res.lhs, res.rhs)
   }
 
   test("pairwise 1") {
@@ -110,18 +104,18 @@ class VersionTest
     ).foreach { case (s1, s2) =>
       val c1 = coursier.core.Version(s1)
       val c2 = coursier.core.Version(s2)
-      c1 should be < c2
-      c2 should be > c1
+      assert(clue(c1) < clue(c2))
+      assert(clue(c2) > clue(c1))
 
       val v1 = Version(s1)
       val v2 = Version(s2)
-      v1 should be < v2
-      v2 should be > v1
+      assert(clue(v1) < clue(v2))
+      assert(clue(v2) > clue(v1))
     }
   }
 
   test("equal") {
-    Version("3.0").compare(Version("3.0.+")) shouldBe 0
+    assertEquals(Version("3.0").compare(Version("3.0.+")), 0)
   }
 
   test("selectNext, table 1") {
@@ -129,8 +123,7 @@ class VersionTest
       List("1.0.0", "1.0.1", "1.0.2", "1.1.0", "1.2.0", "2.0.0", "3.0.0", "3.0.0.1", "3.1")
         .map(Version.apply)
 
-    val nextVersions = Table(
-      ("current", "result"),
+    val nextVersions = List(
       ("1.0.0", Some("1.0.2")),
       ("1.0.1", Some("1.0.2")),
       ("1.0.2", Some("1.2.0")),
@@ -143,14 +136,13 @@ class VersionTest
       ("4", None)
     )
 
-    forAll(nextVersions) { (current, result) =>
-      Version(current).selectNext(allVersions) shouldBe result.map(Version.apply)
+    nextVersions.foreach { case (current, result) =>
+      assertEquals(Version(current).selectNext(allVersions), result.map(Version.apply))
     }
   }
 
   test("selectNext, table 2") {
-    val nextVersions = Table(
-      ("current", "versions", "result"),
+    val nextVersions = List(
       ("1.3.0-RC3", List("1.3.0-RC4", "1.3.0-RC5"), Some("1.3.0-RC5")),
       ("1.3.0-RC3", List("1.3.0-RC4", "1.3.0-RC5", "1.3.0", "1.3.2"), Some("1.3.2")),
       ("3.0-RC3", List("3.0-RC4", "3.0-RC5", "3.0", "3.2"), Some("3.2")),
@@ -223,23 +215,23 @@ class VersionTest
     )
 
     val rnd = new Random()
-    forAll(nextVersions) { (current, versions, result) =>
-      Version(current).selectNext(rnd.shuffle(versions).map(Version.apply)) shouldBe
-        result.map(Version.apply)
+    nextVersions.foreach { case (current, versions, result) =>
+      val obtained = Version(current).selectNext(rnd.shuffle(versions).map(Version.apply))
+      assertEquals(obtained, result.map(Version.apply))
     }
   }
 
   test("Component: round-trip") {
-    forAll { str: String => Component.render(Component.parse(str)) shouldBe str }
+    forAll { str: String => assertEquals(Component.render(Component.parse(str)), str) }
   }
 
   test("Component: round-trip using Version") {
-    forAll { v: Version => Component.render(Component.parse(v.value)) shouldBe v.value }
+    forAll { v: Version => assertEquals(Component.render(Component.parse(v.value)), v.value) }
   }
 
   test("Component: round-trip example") {
     val original = "1.0.0-rc.1+build.1"
-    Component.render(Component.Empty :: Component.parse(original)) shouldBe original
+    assertEquals(Component.render(Component.Empty :: Component.parse(original)), original)
   }
 
   def checkPairwise(versions: List[String]): Unit = {
@@ -248,8 +240,8 @@ class VersionTest
       case Nil    => Nil
     }
     pairs.foreach { case (v1, v2) =>
-      v1 should be < v2
-      v2 should be > v1
+      assert(clue(v1) < clue(v2))
+      assert(clue(v2) > clue(v1))
     }
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala
index 3c7a95a5..6196a3e2 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala
@@ -1,6 +1,7 @@
 package org.scalasteward.core.edit
 
 import better.files.File
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.{GroupId, Update}
 import org.scalasteward.core.mock.MockContext.{config, editAlg}
@@ -9,10 +10,8 @@ import org.scalasteward.core.repoconfig.RepoConfig
 import org.scalasteward.core.scalafmt.scalafmtBinary
 import org.scalasteward.core.util.Nel
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class EditAlgTest extends AnyFunSuite with Matchers {
+class EditAlgTest extends FunSuite {
   private val envVars = List(s"GIT_ASKPASS=${config.gitAskPass}", "VAR1=val1", "VAR2=val2")
   private val gitStatus =
     List("git", "status", "--porcelain", "--untracked-files=no", "--ignore-submodules")
@@ -29,7 +28,7 @@ class EditAlgTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty.add(file1, """val catsVersion = "1.2.0"""").add(file2, ""))
       .unsafeRunSync()
 
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List("test", "-f", file1.pathAsString),
         List("read", file1.pathAsString),
@@ -48,6 +47,8 @@ class EditAlgTest extends AnyFunSuite with Matchers {
       ),
       files = Map(file1 -> """val catsVersion = "1.3.0"""", file2 -> "")
     )
+
+    assertEquals(state, expected)
   }
 
   test("applyUpdate with scalafmt update") {
@@ -66,7 +67,7 @@ class EditAlgTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty.add(scalafmtConf, scalafmtConfContent).add(buildSbt, ""))
       .unsafeRunSync()
 
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List("test", "-f", scalafmtConf.pathAsString),
         List("read", scalafmtConf.pathAsString),
@@ -104,6 +105,8 @@ class EditAlgTest extends AnyFunSuite with Matchers {
         buildSbt -> ""
       )
     )
+
+    assertEquals(state, expected)
   }
 
   test("apply update to ammonite file") {
@@ -122,7 +125,7 @@ class EditAlgTest extends AnyFunSuite with Matchers {
       )
       .unsafeRunSync()
 
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List("test", "-f", file1.pathAsString),
         List("read", file1.pathAsString),
@@ -142,6 +145,8 @@ class EditAlgTest extends AnyFunSuite with Matchers {
         file2 -> """"org.typelevel" %% "cats-core" % "1.3.0""""
       )
     )
+
+    assertEquals(state, expected)
   }
 
   test("reproduce https://github.com/circe/circe-config/pull/40") {
@@ -154,7 +159,7 @@ class EditAlgTest extends AnyFunSuite with Matchers {
       "build.sbt" -> """val config = "1.3.3"""", // the version should have been updated here
       "project/plugins.sbt" -> """addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.4")"""
     )
-    runApplyUpdate(update, original) shouldBe expected
+    assertEquals(runApplyUpdate(update, original), expected)
   }
 
   test("file restriction when sbt update") {
@@ -167,7 +172,7 @@ class EditAlgTest extends AnyFunSuite with Matchers {
       "build.properties" -> """sbt.version=1.2.8""",
       "project/plugins.sbt" -> """addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.2")"""
     )
-    runApplyUpdate(update, original) shouldBe expected
+    assertEquals(runApplyUpdate(update, original), expected)
   }
 
   test("keyword with extra underscore") {
@@ -183,7 +188,7 @@ class EditAlgTest extends AnyFunSuite with Matchers {
       ".travis.yml" -> """ - SCALA_JS_VERSION=1.1.1""",
       "project/plugins.sbt" -> """val scalaJsVersion = Option(System.getenv("SCALA_JS_VERSION")).getOrElse("1.1.1")"""
     )
-    runApplyUpdate(update, original) shouldBe expected
+    assertEquals(runApplyUpdate(update, original), expected)
   }
 
   test("test updating group id and version") {
@@ -207,7 +212,7 @@ class EditAlgTest extends AnyFunSuite with Matchers {
           |"org.typelevel" %% "simulacrum" % simulacrum
           |"""".stripMargin // the version should have been updated here
     )
-    runApplyUpdate(update, original) shouldBe expected
+    assertEquals(runApplyUpdate(update, original), expected)
   }
 
   test("test updating artifact id and version") {
@@ -231,7 +236,7 @@ class EditAlgTest extends AnyFunSuite with Matchers {
           |val test = "com.test" %% "newer-artifact" % testVersion 
           |"""".stripMargin
     )
-    runApplyUpdate(update, original) shouldBe expected
+    assertEquals(runApplyUpdate(update, original), expected)
   }
 
   private def runApplyUpdate(update: Update, files: Map[String, String]): Map[String, String] = {
diff --git a/modules/core/src/test/scala/org/scalasteward/core/edit/UpdateHeuristicTest.scala b/modules/core/src/test/scala/org/scalasteward/core/edit/UpdateHeuristicTest.scala
index 7cf008b0..24d90205 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/edit/UpdateHeuristicTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/edit/UpdateHeuristicTest.scala
@@ -1,19 +1,20 @@
 package org.scalasteward.core.edit
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.Update.{Group, Single}
 import org.scalasteward.core.data.{ArtifactId, GroupId, Update}
 import org.scalasteward.core.edit.UpdateHeuristicTest.UpdateOps
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class UpdateHeuristicTest extends AnyFunSuite with Matchers {
+class UpdateHeuristicTest extends FunSuite {
   test("sbt: build.properties") {
     val original = """sbt.version=1.3.0-RC1"""
     val expected = """sbt.version=1.3.0"""
-    Single("org.scala-sbt" % "sbt" % "1.3.0-RC1", Nel.of("1.3.0"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("org.scala-sbt" % "sbt" % "1.3.0-RC1", Nel.of("1.3.0")).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("sbt plugins") {
@@ -27,8 +28,11 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
         |addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.25")
         |addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "0.4.0")
       """.stripMargin.trim
-    Single("org.scala-js" % "sbt-scalajs" % "0.6.24", Nel.of("0.6.25"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Single("org.scala-js" % "sbt-scalajs" % "0.6.24", Nel.of("0.6.25"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("sbt plugins: missing version") {
@@ -37,43 +41,61 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
         |addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.23")
         |addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "0.4.0")
       """.stripMargin.trim
-    Single("org.scala-js" % "sbt-scalajs" % "0.6.24", Nel.of("0.6.25"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Single("org.scala-js" % "sbt-scalajs" % "0.6.24", Nel.of("0.6.25"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("all on one line") {
     val original = """"be.doeraene" %% "scalajs-jquery"  % "0.9.3""""
     val expected = """"be.doeraene" %% "scalajs-jquery"  % "0.9.4""""
-    Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("ignore hyphen in artifactId") {
     val original = """val scalajsJqueryVersion = "0.9.3""""
     val expected = """val scalajsJqueryVersion = "0.9.4""""
-    Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("with single quotes around val") {
     val original = """val `scalajs-jquery-version` = "0.9.3""""
     val expected = """val `scalajs-jquery-version` = "0.9.4""""
-    Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.relaxed.name)
+    assertEquals(
+      Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.relaxed.name
+    )
   }
 
   test("all upper case") {
     val original = """val SCALAJSJQUERYVERSION = "0.9.3""""
     val expected = """val SCALAJSJQUERYVERSION = "0.9.4""""
-    Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("just artifactId without version") {
     val original = """val scalajsjquery = "0.9.3""""
     val expected = """val scalajsjquery = "0.9.4""""
-    Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("commented val") {
@@ -85,8 +107,11 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       """// val scalajsJqueryVersion = "0.9.3
         |val scalajsJqueryVersion = "0.9.4" //bla
         |"""".stripMargin.trim
-    Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("commented ModuleIDs") {
@@ -102,22 +127,28 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
         |   addSbtPlugin("be.doeraene" %% "scalajs-jquery"  % "0.9.4")
         |   //addSbtPlugin("be.doeraene" %% "scalajs-jquery"  % "0.9.3")
         |"""".stripMargin.trim
-    Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    val update = Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
+    assertEquals(update.replaceVersionIn(original), Some(expected) -> UpdateHeuristic.moduleId.name)
   }
 
   test("ignore '-core' suffix") {
     val original = """val specs2Version = "4.2.0""""
     val expected = """val specs2Version = "4.3.4""""
-    Single("org.specs2" % "specs2-core" % "4.2.0", Nel.of("4.3.4"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("org.specs2" % "specs2-core" % "4.2.0", Nel.of("4.3.4"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("use groupId if artifactId is 'core'") {
     val original = """lazy val sttpVersion = "1.3.2""""
     val expected = """lazy val sttpVersion = "1.3.3""""
-    Single("com.softwaremill.sttp" % "core" % "1.3.2", Nel.of("1.3.3"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("com.softwaremill.sttp" % "core" % "1.3.2", Nel.of("1.3.3"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("short groupIds") {
@@ -133,36 +164,48 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
                       |  ).map("com.sky" %% _ % "1.3.0")
                       |""".stripMargin
 
-    Group("com.sky" % Nel.of("akka-streams", "akka-streams-kafka") % "1.2.0", Nel.one("1.3.0"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.completeGroupId.name)
+    assertEquals(
+      Group("com.sky" % Nel.of("akka-streams", "akka-streams-kafka") % "1.2.0", Nel.one("1.3.0"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.completeGroupId.name
+    )
   }
 
   test("version range") {
     val original = """Seq("org.specs2" %% "specs2-core" % "3.+" % "test")"""
     val expected = """Seq("org.specs2" %% "specs2-core" % "4.3.4" % "test")"""
-    Single("org.specs2" % "specs2-core" % "3.+", Nel.of("4.3.4"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Single("org.specs2" % "specs2-core" % "3.+", Nel.of("4.3.4"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("group with prefix val") {
     val original = """ val circe = "0.10.0-M1" """
     val expected = """ val circe = "0.10.0-M2" """
-    Group(
-      "io.circe" %
-        Nel.of("circe-generic", "circe-literal", "circe-parser", "circe-testing") % "0.10.0-M1",
-      Nel.of("0.10.0-M2")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Group(
+        "io.circe" %
+          Nel.of("circe-generic", "circe-literal", "circe-parser", "circe-testing") % "0.10.0-M1",
+        Nel.of("0.10.0-M2")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("update under different group id") {
     val original = """ "org.spire-math" %% "kind-projector" % "0.9.0""""
     val expected = """ "org.typelevel" %% "kind-projector" % "0.10.0""""
-    Single(
-      "org.spire-math" % "kind-projector" % "0.9.0",
-      Nel.of("0.10.0"),
-      Some(GroupId("org.typelevel")),
-      Some("kind-projector")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Single(
+        "org.spire-math" % "kind-projector" % "0.9.0",
+        Nel.of("0.10.0"),
+        Some(GroupId("org.typelevel")),
+        Some("kind-projector")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("group with repeated version") {
@@ -174,8 +217,11 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       """ "com.pepegar" %% "hammock-core"  % "0.8.5",
         | "com.pepegar" %% "hammock-circe" % "0.8.5"
       """.stripMargin.trim
-    Group("com.pepegar" % Nel.of("hammock-core", "hammock-circe") % "0.8.1", Nel.of("0.8.5"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Group("com.pepegar" % Nel.of("hammock-core", "hammock-circe") % "0.8.1", Nel.of("0.8.5"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("same version, same artifact prefix, different groupId") {
@@ -189,8 +235,11 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
         | "org.typelevel" %% "jawn-json4s"  % "0.14.1",
         | "org.typelevel" %% "jawn-play" % "0.14.1"
       """.stripMargin.trim
-    Group("org.typelevel" % Nel.of("jawn-json4s", "jawn-play") % "0.14.0", Nel.of("0.14.1"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Group("org.typelevel" % Nel.of("jawn-json4s", "jawn-play") % "0.14.0", Nel.of("0.14.1"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("artifactIds are common suffixes") {
@@ -202,8 +251,14 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       """lazy val scalajsReactVersion = "1.3.1"
         |lazy val logbackVersion = "1.2.3"
       """.stripMargin
-    Group("com.github.japgolly.scalajs-react" % Nel.of("core", "extra") % "1.2.3", Nel.of("1.3.1"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Group(
+        "com.github.japgolly.scalajs-react" % Nel.of("core", "extra") % "1.2.3",
+        Nel.of("1.3.1")
+      )
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("ignore 'previous' prefix") {
@@ -215,8 +270,11 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       """val circeVersion = "0.10.1"
         |val previousCirceIterateeVersion = "0.10.0"
       """.stripMargin
-    Group("io.circe" % Nel.of("circe-jawn", "circe-testing") % "0.10.0", Nel.of("0.10.1"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Group("io.circe" % Nel.of("circe-jawn", "circe-testing") % "0.10.0", Nel.of("0.10.1"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("ignore mimaPreviousArtifacts") {
@@ -228,70 +286,97 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       """"io.dropwizard.metrics" % "metrics-core" % "4.0.3"
         |mimaPreviousArtifacts := Set("io.dropwizard.metrics" %% "metrics-core" % "4.0.1")
       """.stripMargin
-    Group(
-      "io.dropwizard.metrics" % Nel.of("metrics-core", "metrics-healthchecks") % "4.0.1",
-      Nel.of("4.0.3")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Group(
+        "io.dropwizard.metrics" % Nel.of("metrics-core", "metrics-healthchecks") % "4.0.1",
+        Nel.of("4.0.3")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("artifactId with dot") {
     val original = """ def plotlyJs = "1.41.3" """
     val expected = """ def plotlyJs = "1.43.2" """
-    Single("org.webjars.bower" % "plotly.js" % "1.41.3", Nel.of("1.43.2"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("org.webjars.bower" % "plotly.js" % "1.41.3", Nel.of("1.43.2"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("val with backticks") {
     val original = """ val `plotly.js` = "1.41.3" """
     val expected = """ val `plotly.js` = "1.43.2" """
-    Single("org.webjars.bower" % "plotly.js" % "1.41.3", Nel.of("1.43.2"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("org.webjars.bower" % "plotly.js" % "1.41.3", Nel.of("1.43.2"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 
   test("word from artifactId") {
     val original = """lazy val circeVersion = "0.9.3""""
     val expected = """lazy val circeVersion = "0.11.1""""
-    Single(
-      "io.circe" % ArtifactId("circe-generic", "circe-generic_2.12") % "0.9.3",
-      Nel.of("0.11.1")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.relaxed.name)
+    assertEquals(
+      Single(
+        "io.circe" % ArtifactId("circe-generic", "circe-generic_2.12") % "0.9.3",
+        Nel.of("0.11.1")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.relaxed.name
+    )
   }
 
   test("artifactId with underscore") {
     val original = """val scShapelessV = "1.1.6""""
     val expected = """val scShapelessV = "1.1.8""""
-    Single("com.github.alexarchambault" % "scalacheck-shapeless_1.13" % "1.1.6", Nel.of("1.1.8"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.relaxed.name)
+    assertEquals(
+      Single("com.github.alexarchambault" % "scalacheck-shapeless_1.13" % "1.1.6", Nel.of("1.1.8"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.relaxed.name
+    )
   }
 
   test("camel case artifactId") {
     val original = """val hikariVersion = "3.3.0" """
     val expected = """val hikariVersion = "3.4.0" """
-    Single("com.zaxxer" % "HikariCP" % "3.3.0", Nel.of("3.4.0"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.relaxed.name)
+    assertEquals(
+      Single("com.zaxxer" % "HikariCP" % "3.3.0", Nel.of("3.4.0"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.relaxed.name
+    )
   }
 
   test("mongo from mongodb") {
     val original = """val mongoVersion = "3.7.0" """
     val expected = """val mongoVersion = "3.7.1" """
-    Group(
-      "org.mongodb" %
-        Nel.of("mongodb-driver", "mongodb-driver-async", "mongodb-driver-core") % "3.7.0",
-      Nel.of("3.7.1")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.sliding.name)
+    assertEquals(
+      Group(
+        "org.mongodb" %
+          Nel.of("mongodb-driver", "mongodb-driver-async", "mongodb-driver-core") % "3.7.0",
+        Nel.of("3.7.1")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.sliding.name
+    )
   }
 
   test("artifactId with common suffix") {
     val original = """case _ => "1.0.2" """
-    Single("co.fs2" % "fs2-core" % "1.0.2", Nel.of("1.0.4"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Single("co.fs2" % "fs2-core" % "1.0.2", Nel.of("1.0.4"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("word from groupId") {
     val original = """val acolyteVersion = "1.0.49" """
     val expected = """val acolyteVersion = "1.0.51" """
-    Single("org.eu.acolyte" % "jdbc-driver" % "1.0.49", Nel.of("1.0.51"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.groupId.name)
+    assertEquals(
+      Single("org.eu.acolyte" % "jdbc-driver" % "1.0.49", Nel.of("1.0.51"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.groupId.name
+    )
   }
 
   test("specific to scalafmt: should be Scala version agnostic") {
@@ -301,33 +386,48 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       ("""version = 2.0.0 """, """version = 2.0.1 """),
       ("""version=2.0.0 """, """version=2.0.1 """)
     ).foreach { case (original, expected) =>
-      Single(
-        "org.scalameta" % ArtifactId("scalafmt-core", "scalafmt-core_2.12") % "2.0.0",
-        Nel.of("2.0.1")
-      ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.specific.name)
+      assertEquals(
+        Single(
+          "org.scalameta" % ArtifactId("scalafmt-core", "scalafmt-core_2.12") % "2.0.0",
+          Nel.of("2.0.1")
+        ).replaceVersionIn(original),
+        Some(expected) -> UpdateHeuristic.specific.name
+      )
     }
 
     val original = """version=2.0.0"""
-    Single("org.scalameta" % "other-artifact" % "2.0.0", Nel.of("2.0.1"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Single("org.scalameta" % "other-artifact" % "2.0.0", Nel.of("2.0.1"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("ignore TLD") {
     val original = """ "com.propensive" %% "contextual" % "1.0.1" """
-    Single("com.slamdata" % "fs2-gzip" % "1.0.1", Nel.of("1.1.1"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Single("com.slamdata" % "fs2-gzip" % "1.0.1", Nel.of("1.1.1"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("ignore short words") {
     val original = "SBT_VERSION=1.2.7"
-    Single("org.scala-sbt" % "scripted-plugin" % "1.2.7", Nel.of("1.2.8"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Single("org.scala-sbt" % "scripted-plugin" % "1.2.7", Nel.of("1.2.8"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("ignore 'scala' substring") {
     val original = """ val scalaTestVersion = "3.0.7" """
-    Single("org.scalactic" % "scalactic" % "3.0.7", Nel.of("3.0.8"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Single("org.scalactic" % "scalactic" % "3.0.7", Nel.of("3.0.8"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("version that contains the current version as proper substring") {
@@ -341,26 +441,35 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       libraryDependencies += "com.thoughtworks.dsl" %%% "keywords-using" % "1.3.0" % Optional
       libraryDependencies += "com.thoughtworks.dsl" %%% "keywords-each"  % "1.2.0+14-7a373cbd" % Optional
       """
-    Group(
-      "com.thoughtworks.dsl" % Nel.of("keywords-each", "keywords-using") % "1.2.0",
-      Nel.of("1.3.0")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Group(
+        "com.thoughtworks.dsl" % Nel.of("keywords-each", "keywords-using") % "1.2.0",
+        Nel.of("1.3.0")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("prevent exception: named capturing group is missing trailing '}'") {
     val original = """ "org.nd4j" % s"nd4j-""" + "$" + """{nd4jRuntime.value}-platform" % "0.8.0""""
     val expected = """ "org.nd4j" % s"nd4j-""" + "$" + """{nd4jRuntime.value}-platform" % "0.9.1""""
-    Group("org.nd4j" % Nel.of("nd4j-api", "nd4j-native-platform") % "0.8.0", Nel.of("0.9.1"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.strict.name)
+    assertEquals(
+      Group("org.nd4j" % Nel.of("nd4j-api", "nd4j-native-platform") % "0.8.0", Nel.of("0.9.1"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.strict.name
+    )
   }
 
   test("NOK: change of unrelated ModuleID") {
     val original = """ "com.geirsson" % "sbt-ci-release" % "1.2.1" """
     val expected = """ "com.geirsson" % "sbt-ci-release" % "1.2.4" """
-    Group(
-      "org.scala-sbt" % Nel.of("sbt-launch", "scripted-plugin", "scripted-sbt") % "1.2.1",
-      Nel.of("1.2.4")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.relaxed.name)
+    assertEquals(
+      Group(
+        "org.scala-sbt" % Nel.of("sbt-launch", "scripted-plugin", "scripted-sbt") % "1.2.1",
+        Nel.of("1.2.4")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.relaxed.name
+    )
   }
 
   test("disable updates on single lines with `off` (no `on`)") {
@@ -372,8 +481,11 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       """  "com.typesafe.akka" %% "akka-actor" % "2.4.0", // scala-steward:off
         |  "com.typesafe.akka" %% "akka-testkit" % "2.5.0",
         |  """.stripMargin.trim
-    Group("com.typesafe.akka" % Nel.of("akka-actor", "akka-testkit") % "2.4.0", Nel.of("2.5.0"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Group("com.typesafe.akka" % Nel.of("akka-actor", "akka-testkit") % "2.4.0", Nel.of("2.5.0"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("disable updates on multiple lines after `off` (no `on`)") {
@@ -382,8 +494,11 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
         |  "com.typesafe.akka" %% "akka-actor" % "2.4.0",
         |  "com.typesafe.akka" %% "akka-testkit" % "2.4.0",
         |  """.stripMargin.trim
-    Group("com.typesafe.akka" % Nel.of("akka-actor", "akka-testkit") % "2.4.0", Nel.of("2.5.0"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Group("com.typesafe.akka" % Nel.of("akka-actor", "akka-testkit") % "2.4.0", Nel.of("2.5.0"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("update multiple lines between `on` and `off`") {
@@ -403,10 +518,13 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
         |  // scala-steward:off
         |  "com.typesafe.akka" %% "akka-testkit" % "2.4.20" % "test"
         |  """.stripMargin.trim
-    Group(
-      "com.typesafe.akka" % Nel.of("akka-actor", "akka-testkit", "akka-slf4j") % "2.4.20",
-      Nel.of("2.5.0")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Group(
+        "com.typesafe.akka" % Nel.of("akka-actor", "akka-testkit", "akka-slf4j") % "2.4.20",
+        Nel.of("2.5.0")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("hash before `off`") {
@@ -414,8 +532,11 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       """# scala-steward:off
         |sbt.version=1.2.8
         |""".stripMargin
-    Single("org.scala-sbt" % "sbt" % "1.2.8", Nel.of("1.4.3"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Single("org.scala-sbt" % "sbt" % "1.2.8", Nel.of("1.4.3"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("similar artifactIds and same version") {
@@ -431,44 +552,59 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
         | "org.typelevel" %%% "cats-effect" % "2.0.0-M4",
         | "org.typelevel" %%% "cats-effect-laws" % "2.0.0-M4" % "test",
         |""".stripMargin
-    Group("org.typelevel" % Nel.of("cats-core", "cats-laws") % "2.0.0-M4", Nel.of("2.0.0-RC1"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Group("org.typelevel" % Nel.of("cats-core", "cats-laws") % "2.0.0-M4", Nel.of("2.0.0-RC1"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("ammonite script syntax") {
     val original = " import $ivy.`org.typelevel::cats-core:1.2.0` ".stripMargin
     val expected = " import $ivy.`org.typelevel::cats-core:1.3.0` ".stripMargin
 
-    Single("org.typelevel" % "cats-core" % "1.2.0", Nel.of("1.3.0"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.moduleId.name)
+    assertEquals(
+      Single("org.typelevel" % "cats-core" % "1.2.0", Nel.of("1.3.0"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.moduleId.name
+    )
   }
 
   test("fail on versions with line break") {
     val original = """val scalajsJqueryVersion =
                      |  "0.9.3"""".stripMargin
-    Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
-      .replaceVersionIn(original)
-      ._1 shouldBe None
+    assertEquals(
+      Single("be.doeraene" % "scalajs-jquery" % "0.9.3", Nel.of("0.9.4"))
+        .replaceVersionIn(original)
+        ._1,
+      None
+    )
   }
 
   test("cognito value for aws-java-sdk-cognitoidp artifact") {
     val original = """val cognito       = "1.11.690" """
     val expected = """val cognito       = "1.11.700" """
-    Single("com.amazonaws" % "aws-java-sdk-cognitoidp" % "1.11.690", Nel.of("1.11.700"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.sliding.name)
+    assertEquals(
+      Single("com.amazonaws" % "aws-java-sdk-cognitoidp" % "1.11.690", Nel.of("1.11.700"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.sliding.name
+    )
   }
 
   test("issue 1586 - tracing value for opentracing library") {
     val original = """val tracing = "2.4.1" """
     val expected = """val tracing = "2.5.0" """
-    Group(
-      "com.colisweb" % Nel.of(
-        "scala-opentracing-core",
-        "scala-opentracing-context",
-        "scala-opentracing-http4s-server-tapir"
-      ) % "2.4.1",
-      Nel.of("2.5.0")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.sliding.name)
+    assertEquals(
+      Group(
+        "com.colisweb" % Nel.of(
+          "scala-opentracing-core",
+          "scala-opentracing-context",
+          "scala-opentracing-http4s-server-tapir"
+        ) % "2.4.1",
+        Nel.of("2.5.0")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.sliding.name
+    )
   }
 
   test("issue 1489: ignore word: scala") {
@@ -480,26 +616,35 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       """ val jsoniter = "2.4.1"
         | addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.0")
         |""".stripMargin
-    Group(
-      "com.github.plokhotnyuk.jsoniter-scala" %
-        Nel.of("jsoniter-scala-core", "jsoniter-scala-macros")
-        % "2.4.0",
-      Nel.of("2.4.1")
-    ).replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.relaxed.name)
+    assertEquals(
+      Group(
+        "com.github.plokhotnyuk.jsoniter-scala" %
+          Nel.of("jsoniter-scala-core", "jsoniter-scala-macros")
+          % "2.4.0",
+        Nel.of("2.4.1")
+      ).replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.relaxed.name
+    )
   }
 
   test("missing enclosing quote before") {
     val original =
       """.add("scalatestplus", version = "3.2.2.0", org = "org.scalatestplus", "scalacheck-1-14")"""
-    Single("org.typelevel" % "cats-effect" % "2.2.0", Nel.of("2.3.0"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Single("org.typelevel" % "cats-effect" % "2.2.0", Nel.of("2.3.0"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("missing enclosing quote after") {
     val original =
       """.add("scalatestplus", version = "2.2.0.3", org = "org.scalatestplus", "scalacheck-1-14")"""
-    Single("org.typelevel" % "cats-effect" % "2.2.0", Nel.of("2.3.0"))
-      .replaceVersionIn(original) shouldBe (None -> UpdateHeuristic.all.last.name)
+    assertEquals(
+      Single("org.typelevel" % "cats-effect" % "2.2.0", Nel.of("2.3.0"))
+        .replaceVersionIn(original),
+      None -> UpdateHeuristic.all.last.name
+    )
   }
 
   test("issue #1651: don't update in comments") {
@@ -507,8 +652,11 @@ class UpdateHeuristicTest extends AnyFunSuite with Matchers {
       """val scalaTest = "3.2.0"  // scalaTest 3.2.0-M2 is causing a failure on scala 2.13..."""
     val expected =
       """val scalaTest = "3.2.2"  // scalaTest 3.2.0-M2 is causing a failure on scala 2.13..."""
-    Single("org.scalatest" % "scalatest" % "3.2.0", Nel.of("3.2.2"))
-      .replaceVersionIn(original) shouldBe (Some(expected) -> UpdateHeuristic.original.name)
+    assertEquals(
+      Single("org.scalatest" % "scalatest" % "3.2.0", Nel.of("3.2.2"))
+        .replaceVersionIn(original),
+      Some(expected) -> UpdateHeuristic.original.name
+    )
   }
 }
 
diff --git a/modules/core/src/test/scala/org/scalasteward/core/edit/editTest.scala b/modules/core/src/test/scala/org/scalasteward/core/edit/editTest.scala
index ef8a1ece..dfed6bbb 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/edit/editTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/edit/editTest.scala
@@ -1,12 +1,11 @@
 package org.scalasteward.core.edit
 
 import cats.syntax.all._
+import munit.ScalaCheckSuite
+import org.scalacheck.Prop._
 import org.scalacheck.{Arbitrary, Gen}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
 
-class editTest extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {
+class editTest extends ScalaCheckSuite {
   private val lineGen = Gen.frequency(
     3 -> Arbitrary.arbString.arbitrary,
     1 -> Gen.oneOf("scala-steward:off", "scala-steward:on"),
@@ -17,7 +16,7 @@ class editTest extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {
 
   test("splitByOffOnMarker") {
     forAll(contentGen) { s: String =>
-      splitByOffOnMarker(s).foldMap { case (part, _) => part } shouldBe s
+      assertEquals(splitByOffOnMarker(s).foldMap { case (part, _) => part }, s)
     }
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/edit/hooks/HookExecutorTest.scala b/modules/core/src/test/scala/org/scalasteward/core/edit/hooks/HookExecutorTest.scala
index b8f633f9..92467c04 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/edit/hooks/HookExecutorTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/edit/hooks/HookExecutorTest.scala
@@ -1,5 +1,6 @@
 package org.scalasteward.core.edit.hooks
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.Update
 import org.scalasteward.core.mock.MockContext.{config, hookExecutor, workspaceAlg}
@@ -8,10 +9,8 @@ import org.scalasteward.core.repoconfig.{RepoConfig, ScalafmtConfig}
 import org.scalasteward.core.scalafmt.{scalafmtArtifactId, scalafmtBinary, scalafmtGroupId}
 import org.scalasteward.core.util.Nel
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class HookExecutorTest extends AnyFunSuite with Matchers {
+class HookExecutorTest extends FunSuite {
   private val repo = Repo("scala-steward-org", "scala-steward")
   private val repoDir = workspaceAlg.repoDir(repo).runA(MockState.empty).unsafeRunSync()
   private val envVars = List(s"GIT_ASKPASS=${config.gitAskPass}", "VAR1=val1", "VAR2=val2")
@@ -23,7 +22,7 @@ class HookExecutorTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty)
       .unsafeRunSync()
 
-    state shouldBe MockState.empty
+    assertEquals(state, MockState.empty)
   }
 
   test("scalafmt: enabled by config") {
@@ -40,7 +39,7 @@ class HookExecutorTest extends AnyFunSuite with Matchers {
       .runS(initial)
       .unsafeRunSync()
 
-    state shouldBe initial.copy(
+    val expected = initial.copy(
       commands = Vector(
         List(
           "VAR1=val1",
@@ -70,6 +69,7 @@ class HookExecutorTest extends AnyFunSuite with Matchers {
       logs = Vector((None, "Executing post-update hook for org.scalameta:scalafmt-core"))
     )
 
+    assertEquals(state, expected)
   }
 
   test("scalafmt: disabled by config") {
@@ -82,7 +82,7 @@ class HookExecutorTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty)
       .unsafeRunSync()
 
-    state shouldBe MockState.empty
+    assertEquals(state, MockState.empty)
   }
 
   test("sbt-github-actions") {
@@ -92,7 +92,7 @@ class HookExecutorTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty)
       .unsafeRunSync()
 
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List(
           repoDir.toString,
@@ -115,5 +115,7 @@ class HookExecutorTest extends AnyFunSuite with Matchers {
       ),
       logs = Vector((None, "Executing post-update hook for com.codecommit:sbt-github-actions"))
     )
+
+    assertEquals(state, expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/git/FileGitAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/git/FileGitAlgTest.scala
index a8911a83..32d6983a 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/git/FileGitAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/git/FileGitAlgTest.scala
@@ -4,6 +4,7 @@ import better.files.File
 import cats.Monad
 import cats.effect.IO
 import cats.syntax.all._
+import munit.FunSuite
 import org.scalasteward.core.TestInstances.ioLogger
 import org.scalasteward.core.git.FileGitAlgTest.{master, Supplement}
 import org.scalasteward.core.io.FileAlgTest.ioFileAlg
@@ -11,10 +12,8 @@ import org.scalasteward.core.io.ProcessAlgTest.ioProcessAlg
 import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg}
 import org.scalasteward.core.mock.MockContext.config
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class FileGitAlgTest extends AnyFunSuite with Matchers {
+class FileGitAlgTest extends FunSuite {
   implicit private val ioWorkspaceAlg: WorkspaceAlg[IO] = WorkspaceAlg.create[IO](config)
   implicit private val ioGitAlg: GenGitAlg[IO, File] =
     new FileGitAlg[IO](config).contramapRepoF(IO.pure)
@@ -28,7 +27,7 @@ class FileGitAlgTest extends AnyFunSuite with Matchers {
       _ <- supplement.createConflict(repo)
       authors <- ioGitAlg.branchAuthors(repo, Branch("conflicts-no"), master)
     } yield authors
-    p.unsafeRunSync() shouldBe List("'Bot Doe'")
+    assertEquals(p.unsafeRunSync(), List("'Bot Doe'"))
   }
 
   test("cloneExists") {
@@ -40,7 +39,7 @@ class FileGitAlgTest extends AnyFunSuite with Matchers {
       _ <- ioGitAlg.removeClone(repo)
       e3 <- ioGitAlg.cloneExists(repo)
     } yield (e1, e2, e3)
-    p.unsafeRunSync() shouldBe ((false, true, false))
+    assertEquals(p.unsafeRunSync(), (false, true, false))
   }
 
   test("containsChanges") {
@@ -56,7 +55,7 @@ class FileGitAlgTest extends AnyFunSuite with Matchers {
       _ <- ioGitAlg.commitAllIfDirty(repo, "Modify test.txt")
       c3 <- ioGitAlg.containsChanges(repo)
     } yield (c1, c2, c3)
-    p.unsafeRunSync() shouldBe ((false, true, false))
+    assertEquals(p.unsafeRunSync(), (false, true, false))
   }
 
   test("currentBranch") {
@@ -67,7 +66,7 @@ class FileGitAlgTest extends AnyFunSuite with Matchers {
       branch <- ioGitAlg.currentBranch(repo)
       _ <- ioGitAlg.latestSha1(repo, branch)
     } yield branch
-    p.unsafeRunSync() shouldBe master
+    assertEquals(p.unsafeRunSync(), master)
   }
 
   test("discardChanges") {
@@ -84,8 +83,8 @@ class FileGitAlgTest extends AnyFunSuite with Matchers {
       after <- ioFileAlg.readFile(file)
     } yield (before, after)
     val (before, after) = p.unsafeRunSync()
-    before shouldBe Some("world")
-    after shouldBe Some("hello")
+    assertEquals(before, Some("world"))
+    assertEquals(after, Some("hello"))
   }
 
   test("findFilesContaining") {
@@ -95,7 +94,7 @@ class FileGitAlgTest extends AnyFunSuite with Matchers {
       _ <- supplement.createConflict(repo)
       files <- ioGitAlg.findFilesContaining(repo, "line1")
     } yield files
-    p.unsafeRunSync() shouldBe List("file1", "file2")
+    assertEquals(p.unsafeRunSync(), List("file1", "file2"))
   }
 
   test("hasConflicts") {
@@ -106,7 +105,7 @@ class FileGitAlgTest extends AnyFunSuite with Matchers {
       c1 <- ioGitAlg.hasConflicts(repo, Branch("conflicts-yes"), master)
       c2 <- ioGitAlg.hasConflicts(repo, Branch("conflicts-no"), master)
     } yield (c1, c2)
-    p.unsafeRunSync() shouldBe ((true, false))
+    assertEquals(p.unsafeRunSync(), (true, false))
   }
 
   test("mergeTheirs") {
@@ -122,7 +121,7 @@ class FileGitAlgTest extends AnyFunSuite with Matchers {
       c2 <- ioGitAlg.hasConflicts(repo, branch, master)
       m2 <- ioGitAlg.isMerged(repo, master, branch)
     } yield (c1, m1, c2, m2)
-    p.unsafeRunSync() shouldBe ((true, false, false, true))
+    assertEquals(p.unsafeRunSync(), (true, false, false, true))
   }
 
   test("mergeTheirs: CONFLICT (modify/delete)") {
@@ -138,11 +137,11 @@ class FileGitAlgTest extends AnyFunSuite with Matchers {
       c2 <- ioGitAlg.hasConflicts(repo, branch, master)
       m2 <- ioGitAlg.isMerged(repo, master, branch)
     } yield (c1, m1, c2, m2)
-    p.unsafeRunSync() shouldBe ((true, false, false, true))
+    assertEquals(p.unsafeRunSync(), (true, false, false, true))
   }
 
   test("version") {
-    ioGitAlg.version.unsafeRunSync().nonEmpty shouldBe true
+    assert(ioGitAlg.version.unsafeRunSync().nonEmpty)
   }
 }
 
diff --git a/modules/core/src/test/scala/org/scalasteward/core/git/gitTest.scala b/modules/core/src/test/scala/org/scalasteward/core/git/gitTest.scala
index 8eb90161..2db463b6 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/git/gitTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/git/gitTest.scala
@@ -1,33 +1,23 @@
 package org.scalasteward.core.git
 
-import org.scalacheck.{Arbitrary, Gen}
-import org.scalasteward.core.TestSyntax._
+import munit.ScalaCheckSuite
+import org.scalacheck.Prop._
+import org.scalasteward.core.TestInstances._
 import org.scalasteward.core.data.Update
-import org.scalasteward.core.data.Update.Single
 import org.scalasteward.core.repoconfig.CommitsConfig
 import org.scalasteward.core.update.show
-import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-
-class gitTest extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {
-  implicit val updateArbitrary: Arbitrary[Update] = Arbitrary(for {
-    groupId <- Gen.alphaStr
-    artifactId <- Gen.alphaStr
-    currentVersion <- Gen.alphaStr
-    newerVersion <- Gen.alphaStr
-  } yield Single(groupId % artifactId % currentVersion, Nel.one(newerVersion)))
 
+class gitTest extends ScalaCheckSuite {
   test("commitMsgFor should work with static message") {
     val commitsConfig = CommitsConfig(Some("Static message"))
-    forAll { update: Update => commitMsgFor(update, commitsConfig) shouldBe "Static message" }
+    forAll { update: Update => assertEquals(commitMsgFor(update, commitsConfig), "Static message") }
   }
 
   test("commitMsgFor should work with default message") {
     val commitsConfig = CommitsConfig(Some("${default}"))
     forAll { update: Update =>
-      commitMsgFor(update, commitsConfig) shouldBe s"Update ${show.oneLiner(update)} to ${update.nextVersion}"
+      val expected = s"Update ${show.oneLiner(update)} to ${update.nextVersion}"
+      assertEquals(commitMsgFor(update, commitsConfig), expected)
     }
   }
 
@@ -35,8 +25,9 @@ class gitTest extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {
     val commitsConfig =
       CommitsConfig(Some("Update ${artifactName} from ${currentVersion} to ${nextVersion}"))
     forAll { update: Update =>
-      commitMsgFor(update, commitsConfig) shouldBe s"Update ${show.oneLiner(update)} from ${update.currentVersion} to ${update.nextVersion}"
+      val expected =
+        s"Update ${show.oneLiner(update)} from ${update.currentVersion} to ${update.nextVersion}"
+      assertEquals(commitMsgFor(update, commitsConfig), expected)
     }
   }
-
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/io/FileAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/io/FileAlgTest.scala
index b9c3a9ef..7b33f2d4 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/io/FileAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/io/FileAlgTest.scala
@@ -2,16 +2,15 @@ package org.scalasteward.core.io
 
 import better.files.File
 import cats.effect.IO
+import munit.FunSuite
 import org.http4s.Uri
 import org.scalacheck.Arbitrary
 import org.scalasteward.core.TestInstances.ioLogger
 import org.scalasteward.core.io.FileAlgTest.ioFileAlg
 import org.scalasteward.core.mock.MockContext.fileAlg
 import org.scalasteward.core.mock.MockState
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class FileAlgTest extends AnyFunSuite with Matchers {
+class FileAlgTest extends FunSuite {
   test("createTemporarily") {
     val file = File.temp / "test-scala-steward3.tmp"
     val content = Arbitrary.arbitrary[String].sample.getOrElse("")
@@ -22,7 +21,7 @@ class FileAlgTest extends AnyFunSuite with Matchers {
       after <- ioFileAlg.readFile(file)
     } yield (before, during, after)
 
-    p.unsafeRunSync() shouldBe ((None, Some(content), None))
+    assertEquals(p.unsafeRunSync(), (None, Some(content), None))
   }
 
   test("writeFile *> readFile <* deleteForce") {
@@ -31,7 +30,7 @@ class FileAlgTest extends AnyFunSuite with Matchers {
     val read = ioFileAlg.writeFile(file, content) *>
       ioFileAlg.readFile(file).map(_.getOrElse("")) <*
       ioFileAlg.deleteForce(file)
-    read.unsafeRunSync() shouldBe content
+    assertEquals(read.unsafeRunSync(), content)
   }
 
   test("removeTemporarily") {
@@ -45,12 +44,12 @@ class FileAlgTest extends AnyFunSuite with Matchers {
       after <- ioFileAlg.readFile(file)
     } yield (before, during, after)
 
-    p.unsafeRunSync() shouldBe ((Some(content), None, Some(content)))
+    assertEquals(p.unsafeRunSync(), (Some(content), None, Some(content)))
   }
 
   test("removeTemporarily: nonexistent file") {
     val file = File.temp / "does-not-exists.txt"
-    ioFileAlg.removeTemporarily(file)(IO.pure(42)).unsafeRunSync() shouldBe 42
+    assertEquals(ioFileAlg.removeTemporarily(file)(IO.pure(42)).unsafeRunSync(), 42)
   }
 
   test("editFile: nonexistent file") {
@@ -59,12 +58,13 @@ class FileAlgTest extends AnyFunSuite with Matchers {
       edited <- fileAlg.editFile(home / "does-not-exists.txt", Some.apply)
     } yield edited).run(MockState.empty).unsafeRunSync()
 
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List("read", "/tmp/steward/does-not-exists.txt")
       )
     )
-    edited shouldBe false
+    assertEquals(state, expected)
+    assert(!edited)
   }
 
   test("editFile: existent file") {
@@ -75,7 +75,7 @@ class FileAlgTest extends AnyFunSuite with Matchers {
       edited <- fileAlg.editFile(file, edit)
     } yield edited).run(MockState.empty).unsafeRunSync()
 
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List("write", file.pathAsString),
         List("read", file.pathAsString),
@@ -83,7 +83,8 @@ class FileAlgTest extends AnyFunSuite with Matchers {
       ),
       files = Map(file -> "143")
     )
-    edited shouldBe true
+    assertEquals(state, expected)
+    assert(edited)
   }
 
   test("deleteForce removes dangling symlink in subdirectory") {
@@ -100,7 +101,7 @@ class FileAlgTest extends AnyFunSuite with Matchers {
       _ <- ioFileAlg.deleteForce(dir)
       symlinkExists <- IO(symlink.exists(File.LinkOptions.noFollow))
     } yield symlinkExists
-    p.unsafeRunSync() shouldBe false
+    assertEquals(p.unsafeRunSync(), false)
   }
 
   test("readUri: local file without scheme") {
@@ -110,7 +111,7 @@ class FileAlgTest extends AnyFunSuite with Matchers {
       _ <- ioFileAlg.writeFile(file, content)
       read <- ioFileAlg.readUri(Uri.unsafeFromString(file.toString))
     } yield read
-    p.unsafeRunSync() shouldBe content
+    assertEquals(p.unsafeRunSync(), content)
   }
 }
 
diff --git a/modules/core/src/test/scala/org/scalasteward/core/io/ProcessAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/io/ProcessAlgTest.scala
index 501d22ee..0fbff244 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/io/ProcessAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/io/ProcessAlgTest.scala
@@ -3,29 +3,31 @@ package org.scalasteward.core.io
 import better.files.File
 import cats.effect.{Blocker, IO}
 import java.util.concurrent.Executors
+import munit.FunSuite
 import org.scalasteward.core.TestInstances._
 import org.scalasteward.core.application.Config.{ProcessCfg, SandboxCfg}
 import org.scalasteward.core.io.ProcessAlgTest.ioProcessAlg
 import org.scalasteward.core.mock.MockContext.config
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 import scala.concurrent.duration.Duration
 
-class ProcessAlgTest extends AnyFunSuite with Matchers {
+class ProcessAlgTest extends FunSuite {
   test("exec: echo") {
-    ioProcessAlg
+    val obtained = ioProcessAlg
       .exec(Nel.of("echo", "-n", "hello"), File.currentWorkingDirectory)
-      .unsafeRunSync() shouldBe List("hello")
+      .unsafeRunSync()
+    assertEquals(obtained, List("hello"))
   }
 
   test("exec: ls --foo") {
-    ioProcessAlg
-      .exec(Nel.of("ls", "--foo"), File.currentWorkingDirectory)
-      .attempt
-      .map(_.isLeft)
-      .unsafeRunSync()
+    assert(
+      ioProcessAlg
+        .exec(Nel.of("ls", "--foo"), File.currentWorkingDirectory)
+        .attempt
+        .map(_.isLeft)
+        .unsafeRunSync()
+    )
   }
 
   test("execSandboxed: echo with enableSandbox = false") {
@@ -36,11 +38,13 @@ class ProcessAlgTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty)
       .unsafeRunSync()
 
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List(File.temp.toString, "echo", "hello")
       )
     )
+
+    assertEquals(state, expected)
   }
 
   test("execSandboxed: echo with enableSandbox = true") {
@@ -51,7 +55,7 @@ class ProcessAlgTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty)
       .unsafeRunSync()
 
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         List(
           File.temp.toString,
@@ -63,6 +67,8 @@ class ProcessAlgTest extends AnyFunSuite with Matchers {
         )
       )
     )
+
+    assertEquals(state, expected)
   }
 }
 
diff --git a/modules/core/src/test/scala/org/scalasteward/core/io/processTest.scala b/modules/core/src/test/scala/org/scalasteward/core/io/processTest.scala
index 7e027226..41de9b7e 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/io/processTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/io/processTest.scala
@@ -1,15 +1,14 @@
 package org.scalasteward.core.io
 
 import cats.effect.IO
+import munit.FunSuite
 import org.scalasteward.core.TestInstances._
 import org.scalasteward.core.io.ProcessAlgTest.blocker
 import org.scalasteward.core.io.process.Args
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 import scala.concurrent.duration._
 
-class processTest extends AnyFunSuite with Matchers {
+class processTest extends FunSuite {
   def slurp1(cmd: Nel[String]): IO[List[String]] =
     process.slurp[IO](Args(cmd), 1.minute, _ => IO.unit, blocker)
 
@@ -17,26 +16,29 @@ class processTest extends AnyFunSuite with Matchers {
     process.slurp[IO](Args(cmd), timeout, _ => IO.unit, blocker)
 
   test("echo hello") {
-    slurp1(Nel.of("echo", "-n", "hello")).unsafeRunSync() shouldBe List("hello")
+    assertEquals(slurp1(Nel.of("echo", "-n", "hello")).unsafeRunSync(), List("hello"))
   }
 
   test("echo hello world") {
-    slurp1(Nel.of("echo", "-n", "hello\nworld")).unsafeRunSync() shouldBe List("hello", "world")
+    assertEquals(
+      slurp1(Nel.of("echo", "-n", "hello\nworld")).unsafeRunSync(),
+      List("hello", "world")
+    )
   }
 
   test("ls") {
-    slurp1(Nel.of("ls")).attempt.unsafeRunSync().isRight shouldBe true
+    assert(slurp1(Nel.of("ls")).attempt.unsafeRunSync().isRight)
   }
 
   test("ls --foo") {
-    slurp1(Nel.of("ls", "--foo")).attempt.unsafeRunSync().isLeft shouldBe true
+    assert(slurp1(Nel.of("ls", "--foo")).attempt.unsafeRunSync().isLeft)
   }
 
   test("sleep 1: ok") {
-    slurp2(Nel.of("sleep", "1"), 2.seconds).unsafeRunSync() shouldBe List()
+    assertEquals(slurp2(Nel.of("sleep", "1"), 2.seconds).unsafeRunSync(), List())
   }
 
   test("sleep 1: fail") {
-    slurp2(Nel.of("sleep", "1"), 500.milliseconds).attempt.unsafeRunSync().isLeft shouldBe true
+    assert(slurp2(Nel.of("sleep", "1"), 500.milliseconds).attempt.unsafeRunSync().isLeft)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/nurture/NurtureAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/nurture/NurtureAlgTest.scala
index 1c3466b0..81bdc2e5 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/nurture/NurtureAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/nurture/NurtureAlgTest.scala
@@ -3,34 +3,24 @@ package org.scalasteward.core.nurture
 import cats.data.StateT
 import cats.effect.IO
 import eu.timepit.refined.types.numeric.PosInt
-import org.scalacheck.{Arbitrary, Gen}
-import org.scalasteward.core.TestSyntax._
+import munit.ScalaCheckSuite
+import org.scalacheck.Prop._
+import org.scalasteward.core.TestInstances._
 import org.scalasteward.core.data.ProcessResult.{Ignored, Updated}
-import org.scalasteward.core.data.Update.Single
 import org.scalasteward.core.data.{ProcessResult, Update}
-import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-
-class NurtureAlgTest extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {
-  implicit val updateArbitrary: Arbitrary[Update] = Arbitrary(for {
-    groupId <- Gen.alphaStr
-    artifactId <- Gen.alphaStr
-    currentVersion <- Gen.alphaStr
-    newerVersion <- Gen.alphaStr
-  } yield Single(groupId % artifactId % currentVersion, Nel.one(newerVersion)))
 
+class NurtureAlgTest extends ScalaCheckSuite {
   test("processUpdates with No Limiting") {
     forAll { updates: List[Update] =>
-      NurtureAlg
+      val obtained = NurtureAlg
         .processUpdates(
           updates,
           _ => StateT[IO, Int, ProcessResult](actionAcc => IO.pure(actionAcc + 1 -> Ignored)),
           None
         )
         .runS(0)
-        .unsafeRunSync() shouldBe updates.size
+        .unsafeRunSync()
+      assertEquals(obtained, updates.size)
     }
   }
 
@@ -41,14 +31,15 @@ class NurtureAlgTest extends AnyFunSuite with Matchers with ScalaCheckPropertyCh
         StateT[IO, Int, ProcessResult](actionAcc =>
           IO.pure(actionAcc + 1 -> (if (ignorableUpdates.contains(update)) Ignored else Updated))
         )
-      NurtureAlg
+      val obtained = NurtureAlg
         .processUpdates(
           ignorableUpdates ++ appliableUpdates,
           f,
           PosInt.unapply(appliableUpdates.size)
         )
         .runS(0)
-        .unsafeRunSync() shouldBe updates.size
+        .unsafeRunSync()
+      assertEquals(obtained, updates.size)
     }
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/nurture/PullRequestRepositoryTest.scala b/modules/core/src/test/scala/org/scalasteward/core/nurture/PullRequestRepositoryTest.scala
index d1fcec97..a0cca0c4 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/nurture/PullRequestRepositoryTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/nurture/PullRequestRepositoryTest.scala
@@ -1,5 +1,6 @@
 package org.scalasteward.core.nurture
 
+import munit.FunSuite
 import org.http4s.Uri
 import org.http4s.syntax.literals._
 import org.scalasteward.core.TestSyntax._
@@ -10,12 +11,10 @@ import org.scalasteward.core.mock.MockContext.{config, pullRequestRepository}
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.util.Nel
 import org.scalasteward.core.vcs.data.{PullRequestNumber, PullRequestState, Repo}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class PullRequestRepositoryTest extends AnyFunSuite with Matchers {
-  private def checkCommands(state: MockState, commands: Vector[List[String]]) =
-    state.copy(files = Map.empty) shouldBe MockState.empty.copy(commands = commands)
+class PullRequestRepositoryTest extends FunSuite {
+  private def checkCommands(state: MockState, commands: Vector[List[String]]): Unit =
+    assertEquals(state.copy(files = Map.empty), MockState.empty.copy(commands = commands))
 
   withStoreData { (repo, url, sha1, number) =>
     test("createOrUpdate >> findPullRequest >> lastPullRequestCreatedAt") {
@@ -36,8 +35,8 @@ class PullRequestRepositoryTest extends AnyFunSuite with Matchers {
       val (state, (result, createdAt)) = p.run(MockState.empty).unsafeRunSync()
 
       val store = config.workspace / "store/pull_requests/v2/typelevel/cats/pull_requests.json"
-      result shouldBe Some((url, sha1, PullRequestState.Open))
-      createdAt.isDefined shouldBe true
+      assertEquals(result, Some((url, sha1, PullRequestState.Open)))
+      assert(createdAt.isDefined)
 
       checkCommands(
         state,
@@ -70,9 +69,9 @@ class PullRequestRepositoryTest extends AnyFunSuite with Matchers {
       } yield (emptyResult, result, closedResult)
       val (state, (emptyResult, result, closedResult)) = p.run(MockState.empty).unsafeRunSync()
       val store = config.workspace / "store/pull_requests/v2/typelevel/cats/pull_requests.json"
-      emptyResult shouldBe List.empty
-      closedResult shouldBe List.empty
-      result shouldBe List((number, url, TestData.Updates.PortableScala))
+      assertEquals(emptyResult, List.empty)
+      assertEquals(closedResult, List.empty)
+      assertEquals(result, List((number, url, TestData.Updates.PortableScala)))
 
       checkCommands(
         state,
@@ -105,8 +104,8 @@ class PullRequestRepositoryTest extends AnyFunSuite with Matchers {
       } yield (emptyResult, result)
       val (state, (emptyResult, result)) = p.run(MockState.empty).unsafeRunSync()
       val store = config.workspace / "store/pull_requests/v2/typelevel/cats/pull_requests.json"
-      emptyResult shouldBe List.empty
-      result shouldBe List.empty
+      assertEquals(emptyResult, List.empty)
+      assertEquals(result, List.empty)
 
       checkCommands(
         state,
@@ -137,8 +136,8 @@ class PullRequestRepositoryTest extends AnyFunSuite with Matchers {
       } yield (emptyResult, result)
       val (state, (emptyResult, result)) = p.run(MockState.empty).unsafeRunSync()
       val store = config.workspace / "store/pull_requests/v2/typelevel/cats/pull_requests.json"
-      emptyResult shouldBe List.empty
-      result shouldBe List.empty
+      assertEquals(emptyResult, List.empty)
+      assertEquals(result, List.empty)
 
       checkCommands(
         state,
@@ -155,7 +154,7 @@ class PullRequestRepositoryTest extends AnyFunSuite with Matchers {
   private def withStoreData(f: (Repo, Uri, Sha1, PullRequestNumber) => Unit): Unit = {
     val repo = Repo("typelevel", "cats")
     val url = uri"https://github.com/typelevel/cats/pull/3291"
-    val sha1 = Sha1(HexString("a2ced5793c2832ada8c14ba5c77e51c4bc9656a8"))
+    val sha1 = Sha1(HexString.unsafeFrom("a2ced5793c2832ada8c14ba5c77e51c4bc9656a8"))
     val number = PullRequestNumber(3291)
 
     f(repo, url, sha1, number)
diff --git a/modules/core/src/test/scala/org/scalasteward/core/persistence/JsonKeyValueStoreTest.scala b/modules/core/src/test/scala/org/scalasteward/core/persistence/JsonKeyValueStoreTest.scala
index cc37f10a..5a9c57bf 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/persistence/JsonKeyValueStoreTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/persistence/JsonKeyValueStoreTest.scala
@@ -1,11 +1,10 @@
 package org.scalasteward.core.persistence
 
+import munit.FunSuite
 import org.scalasteward.core.mock.MockContext._
 import org.scalasteward.core.mock.{MockEff, MockState}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class JsonKeyValueStoreTest extends AnyFunSuite with Matchers {
+class JsonKeyValueStoreTest extends FunSuite {
   test("put, get") {
     val kvStore = new JsonKeyValueStore[MockEff, String, String]("test", "0")
     val p = for {
@@ -19,8 +18,8 @@ class JsonKeyValueStoreTest extends AnyFunSuite with Matchers {
     val k1File = config.workspace / "store" / "test" / "v0" / "k1" / "test.json"
     val k2File = config.workspace / "store" / "test" / "v0" / "k2" / "test.json"
     val k3File = config.workspace / "store" / "test" / "v0" / "k3" / "test.json"
-    value shouldBe (Some("v1") -> None)
-    state shouldBe MockState.empty.copy(
+    assertEquals(value, (Some("v1") -> None))
+    val expected = MockState.empty.copy(
       commands = Vector(
         List("write", k1File.toString),
         List("read", k1File.toString),
@@ -32,6 +31,7 @@ class JsonKeyValueStoreTest extends AnyFunSuite with Matchers {
         k2File -> """"v2""""
       )
     )
+    assertEquals(state, expected)
   }
 
   test("update") {
@@ -40,6 +40,6 @@ class JsonKeyValueStoreTest extends AnyFunSuite with Matchers {
       _ <- kvStore.update("k1")(_.fold("v0")(_ + "v1"))
       v1 <- kvStore.get("k1")
     } yield v1
-    p.runA(MockState.empty).unsafeRunSync() shouldBe Some("v0")
+    assertEquals(p.runA(MockState.empty).unsafeRunSync(), Some("v0"))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/CommitsConfigTest.scala b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/CommitsConfigTest.scala
index 144e8b45..953e75b9 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/CommitsConfigTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/CommitsConfigTest.scala
@@ -1,17 +1,10 @@
 package org.scalasteward.core.repoconfig
 
 import cats.kernel.laws.discipline.SemigroupTests
+import munit.DisciplineSuite
 import org.scalacheck.Arbitrary
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.prop.Configuration
-import org.typelevel.discipline.scalatest.FunSuiteDiscipline
 
-class CommitsConfigTest
-    extends AnyFunSuite
-    with Matchers
-    with FunSuiteDiscipline
-    with Configuration {
+class CommitsConfigTest extends DisciplineSuite {
   implicit val commitsConfigArbitrary: Arbitrary[CommitsConfig] = Arbitrary(for {
     e <- Arbitrary.arbitrary[Option[String]]
   } yield CommitsConfig(e))
diff --git a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/PullRequestFrequencyTest.scala b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/PullRequestFrequencyTest.scala
index a29c90a5..4f4576de 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/PullRequestFrequencyTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/PullRequestFrequencyTest.scala
@@ -2,43 +2,42 @@ package org.scalasteward.core.repoconfig
 
 import io.circe.parser
 import io.circe.syntax._
+import munit.FunSuite
 import org.scalasteward.core.util.Timestamp
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 import scala.concurrent.duration._
 
-class PullRequestFrequencyTest extends AnyFunSuite with Matchers {
+class PullRequestFrequencyTest extends FunSuite {
   val epoch: Timestamp = Timestamp(0L)
 
   test("onSchedule") {
     val Right(thursday) = PullRequestFrequency.fromString("0 * ? * THU")
     val Right(notThursday) = PullRequestFrequency.fromString("0 * ? * MON-WED,FRI-SUN")
-    thursday.onSchedule(epoch) shouldBe true
-    notThursday.onSchedule(epoch) shouldBe false
+    assert(thursday.onSchedule(epoch))
+    assert(!notThursday.onSchedule(epoch))
   }
 
   test("waitingTime: @asap") {
     val Right(freq) = PullRequestFrequency.fromString("@asap")
-    freq.waitingTime(epoch, Timestamp(18.hours.toMillis)) shouldBe None
+    assertEquals(freq.waitingTime(epoch, Timestamp(18.hours.toMillis)), None)
   }
 
   test("waitingTime: @daily") {
     val Right(freq) = PullRequestFrequency.fromString("@daily")
-    freq.waitingTime(epoch, Timestamp(18.hours.toMillis)) shouldBe Some(6.hours)
+    assertEquals(freq.waitingTime(epoch, Timestamp(18.hours.toMillis)), Some(6.hours))
   }
 
   test("waitingTime: timespan") {
     val Right(freq) = PullRequestFrequency.fromString("14 days")
-    freq.waitingTime(epoch, Timestamp(18.hours.toMillis)) shouldBe Some(6.hours + 13.days)
+    assertEquals(freq.waitingTime(epoch, Timestamp(18.hours.toMillis)), Some(6.hours + 13.days))
   }
 
   test("waitingTime: cron expr") {
     val Right(freq) = PullRequestFrequency.fromString("0 1 ? * *")
-    freq.waitingTime(epoch, Timestamp(20.minutes.toMillis)) shouldBe Some(40.minutes)
+    assertEquals(freq.waitingTime(epoch, Timestamp(20.minutes.toMillis)), Some(40.minutes))
   }
 
   test("CronExpr encode and then decode") {
     val Right(freq) = PullRequestFrequency.fromString("0 0 1,15 * ?")
-    parser.decode[PullRequestFrequency](freq.asJson.spaces2) shouldBe Right(freq)
+    assertEquals(parser.decode[PullRequestFrequency](freq.asJson.spaces2), Right(freq))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/PullRequestsConfigTest.scala b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/PullRequestsConfigTest.scala
index ce21ddae..e4c41221 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/PullRequestsConfigTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/PullRequestsConfigTest.scala
@@ -1,20 +1,12 @@
 package org.scalasteward.core.repoconfig
 
 import cats.kernel.laws.discipline.SemigroupTests
+import munit.DisciplineSuite
 import org.scalacheck.{Arbitrary, Gen}
 import org.scalasteward.core.repoconfig.PullRequestFrequency.{Asap, Timespan}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.prop.Configuration
-import org.typelevel.discipline.scalatest.FunSuiteDiscipline
 import scala.concurrent.duration._
 
-class PullRequestsConfigTest
-    extends AnyFunSuite
-    with Matchers
-    with FunSuiteDiscipline
-    with Configuration {
-
+class PullRequestsConfigTest extends DisciplineSuite {
   implicit val pullRequestFrequencyArbitrary: Arbitrary[PullRequestFrequency] =
     Arbitrary(Arbitrary.arbitrary[FiniteDuration].flatMap(fd => Gen.oneOf(Asap, Timespan(fd))))
 
diff --git a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/RepoConfigAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/RepoConfigAlgTest.scala
index 285a77b3..314a19ad 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/RepoConfigAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/RepoConfigAlgTest.scala
@@ -2,17 +2,16 @@ package org.scalasteward.core.repoconfig
 
 import better.files.File
 import eu.timepit.refined.types.numeric.PosInt
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.{GroupId, Update}
 import org.scalasteward.core.mock.MockContext.repoConfigAlg
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.util.Nel
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 import scala.concurrent.duration._
 
-class RepoConfigAlgTest extends AnyFunSuite with Matchers {
+class RepoConfigAlgTest extends FunSuite {
   test("config with all fields set") {
     val repo = Repo("fthomas", "scala-steward")
     val configFile = File.temp / "ws/fthomas/scala-steward/.scala-steward.conf"
@@ -34,7 +33,7 @@ class RepoConfigAlgTest extends AnyFunSuite with Matchers {
     val initialState = MockState.empty.add(configFile, content)
     val config = repoConfigAlg.readRepoConfigWithDefault(repo).runA(initialState).unsafeRunSync()
 
-    config shouldBe RepoConfig(
+    val expected = RepoConfig(
       pullRequests = PullRequestsConfig(frequency = Some(PullRequestFrequency.Timespan(7.days))),
       updates = UpdatesConfig(
         allow = List(UpdatePattern(GroupId("eu.timepit"), None, None)),
@@ -71,62 +70,83 @@ class RepoConfigAlgTest extends AnyFunSuite with Matchers {
         message = Some("Update ${artifactName} from ${currentVersion} to ${nextVersion}")
       )
     )
+    assertEquals(config, expected)
   }
 
   test("config with 'updatePullRequests = false'") {
     val content = "updatePullRequests = false"
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.Never)))
+    assertEquals(
+      config,
+      Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.Never)))
+    )
   }
 
   test("config with 'updatePullRequests = true'") {
     val content = "updatePullRequests = true"
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(
-      RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.OnConflicts))
+    assertEquals(
+      config,
+      Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.OnConflicts)))
     )
   }
 
   test("config with 'updatePullRequests = always'") {
     val content = """updatePullRequests = "always" """
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.Always)))
+    assertEquals(
+      config,
+      Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.Always)))
+    )
   }
 
   test("config with 'updatePullRequests = on-conflicts'") {
     val content = """updatePullRequests = "on-conflicts" """
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(
-      RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.OnConflicts))
+    assertEquals(
+      config,
+      Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.OnConflicts)))
     )
   }
 
   test("config with 'updatePullRequests = never'") {
     val content = """updatePullRequests = "never" """
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.Never)))
+    assertEquals(
+      config,
+      Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.Never)))
+    )
   }
 
   test("config with 'updatePullRequests = foo'") {
     val content = """updatePullRequests = foo """
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.default)))
+    assertEquals(
+      config,
+      Right(RepoConfig(updatePullRequests = Some(PullRequestUpdateStrategy.default)))
+    )
   }
 
   test("config with 'pullRequests.frequency = @asap'") {
     val content = """pullRequests.frequency = "@asap" """
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(
-      RepoConfig(pullRequests = PullRequestsConfig(frequency = Some(PullRequestFrequency.Asap)))
+    assertEquals(
+      config,
+      Right(
+        RepoConfig(pullRequests = PullRequestsConfig(frequency = Some(PullRequestFrequency.Asap)))
+      )
     )
   }
 
   test("config with 'pullRequests.frequency = @daily'") {
     val content = """pullRequests.frequency = "@daily" """
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(
-      RepoConfig(pullRequests =
-        PullRequestsConfig(frequency = Some(PullRequestFrequency.Timespan(1.day)))
+    assertEquals(
+      config,
+      Right(
+        RepoConfig(pullRequests =
+          PullRequestsConfig(frequency = Some(PullRequestFrequency.Timespan(1.day)))
+        )
       )
     )
   }
@@ -134,9 +154,12 @@ class RepoConfigAlgTest extends AnyFunSuite with Matchers {
   test("config with 'pullRequests.frequency = @monthly'") {
     val content = """pullRequests.frequency = "@monthly" """
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(
-      RepoConfig(pullRequests =
-        PullRequestsConfig(frequency = Some(PullRequestFrequency.Timespan(30.days)))
+    assertEquals(
+      config,
+      Right(
+        RepoConfig(pullRequests =
+          PullRequestsConfig(frequency = Some(PullRequestFrequency.Timespan(30.days)))
+        )
       )
     )
   }
@@ -144,8 +167,11 @@ class RepoConfigAlgTest extends AnyFunSuite with Matchers {
   test("config with 'scalafmt.runAfterUpgrading = true'") {
     val content = "scalafmt.runAfterUpgrading = true"
     val config = RepoConfigAlg.parseRepoConfig(content)
-    config shouldBe Right(
-      RepoConfig(scalafmt = ScalafmtConfig(runAfterUpgrading = Some(true)))
+    assertEquals(
+      config,
+      Right(
+        RepoConfig(scalafmt = ScalafmtConfig(runAfterUpgrading = Some(true)))
+      )
     )
   }
 
@@ -156,9 +182,9 @@ class RepoConfigAlgTest extends AnyFunSuite with Matchers {
     val (state, config) =
       repoConfigAlg.readRepoConfigWithDefault(repo).run(initialState).unsafeRunSync()
 
-    config shouldBe RepoConfig()
-    state.logs.headOption.map { case (_, msg) => msg }.getOrElse("") should
-      startWith("Failed to parse .scala-steward.conf")
+    assertEquals(config, RepoConfig())
+    val log = state.logs.headOption.map { case (_, msg) => msg }.getOrElse("")
+    assert(clue(log).startsWith("Failed to parse .scala-steward.conf"))
   }
 
   test("configToIgnoreFurtherUpdates with single update") {
@@ -167,9 +193,10 @@ class RepoConfigAlgTest extends AnyFunSuite with Matchers {
       .parseRepoConfig(RepoConfigAlg.configToIgnoreFurtherUpdates(update))
       .getOrElse(RepoConfig())
 
-    repoConfig shouldBe RepoConfig(
-      updates = UpdatesConfig(
-        ignore = List(UpdatePattern(GroupId("a"), Some("b"), None))
+    assertEquals(
+      repoConfig,
+      RepoConfig(updates =
+        UpdatesConfig(ignore = List(UpdatePattern(GroupId("a"), Some("b"), None)))
       )
     )
   }
@@ -180,8 +207,9 @@ class RepoConfigAlgTest extends AnyFunSuite with Matchers {
       .parseRepoConfig(RepoConfigAlg.configToIgnoreFurtherUpdates(update))
       .getOrElse(RepoConfig())
 
-    repoConfig shouldBe RepoConfig(
-      updates = UpdatesConfig(ignore = List(UpdatePattern(GroupId("a"), None, None)))
+    assertEquals(
+      repoConfig,
+      RepoConfig(updates = UpdatesConfig(ignore = List(UpdatePattern(GroupId("a"), None, None))))
     )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/RepoConfigTest.scala b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/RepoConfigTest.scala
index 4d52d2a3..774e9dd9 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/RepoConfigTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/RepoConfigTest.scala
@@ -1,14 +1,13 @@
 package org.scalasteward.core.repoconfig
 
 import cats.syntax.semigroup._
+import munit.FunSuite
 import org.scalasteward.core.data.GroupId
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 import scala.concurrent.duration._
 
-class RepoConfigTest extends AnyFunSuite with Matchers {
+class RepoConfigTest extends FunSuite {
   test("RepoConfig: semigroup") {
-    RepoConfig.empty |+| RepoConfig.empty shouldBe RepoConfig.empty
+    assertEquals(RepoConfig.empty |+| RepoConfig.empty, RepoConfig.empty)
 
     val cfg = RepoConfig(
       commits = CommitsConfig(Some("a")),
@@ -20,9 +19,9 @@ class RepoConfigTest extends AnyFunSuite with Matchers {
       updatePullRequests = Some(PullRequestUpdateStrategy.Always)
     )
 
-    cfg |+| RepoConfig.empty shouldBe cfg
-    RepoConfig.empty |+| cfg shouldBe cfg
-    cfg |+| cfg shouldBe cfg
+    assertEquals(cfg |+| RepoConfig.empty, cfg)
+    assertEquals(RepoConfig.empty |+| cfg, cfg)
+    assertEquals(cfg |+| cfg, cfg)
 
     val cfg2 = RepoConfig(
       commits = CommitsConfig(Some("b")),
@@ -34,16 +33,14 @@ class RepoConfigTest extends AnyFunSuite with Matchers {
       updatePullRequests = Some(PullRequestUpdateStrategy.OnConflicts)
     )
 
-    cfg |+| cfg2 shouldBe cfg.copy(
-      updates = UpdatesConfig(
-        allow = List(UpdatePattern(GroupId("B"), None, None))
-      )
+    assertEquals(
+      cfg |+| cfg2,
+      cfg.copy(updates = UpdatesConfig(allow = List(UpdatePattern(GroupId("B"), None, None))))
     )
 
-    cfg2 |+| cfg shouldBe cfg2.copy(
-      updates = UpdatesConfig(
-        allow = List(UpdatePattern(GroupId("B"), None, None))
-      )
+    assertEquals(
+      cfg2 |+| cfg,
+      cfg2.copy(updates = UpdatesConfig(allow = List(UpdatePattern(GroupId("B"), None, None))))
     )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/UpdatesConfigTest.scala b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/UpdatesConfigTest.scala
index ccef4148..989fe702 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/repoconfig/UpdatesConfigTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/repoconfig/UpdatesConfigTest.scala
@@ -2,12 +2,11 @@ package org.scalasteward.core.repoconfig
 
 import cats.syntax.semigroup._
 import eu.timepit.refined.types.numeric.PosInt
+import munit.FunSuite
 import org.scalasteward.core.data.GroupId
 import org.scalasteward.core.repoconfig.UpdatePattern.Version
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class UpdatesConfigTest extends AnyFunSuite with Matchers {
+class UpdatesConfigTest extends FunSuite {
 
   private val groupIdA = GroupId("A")
   private val groupIdB = GroupId("B")
@@ -25,105 +24,123 @@ class UpdatesConfigTest extends AnyFunSuite with Matchers {
 
   test("semigroup: basic checks") {
     val emptyCfg = UpdatesConfig()
-    emptyCfg |+| emptyCfg shouldBe emptyCfg
+    assertEquals(emptyCfg |+| emptyCfg, emptyCfg)
 
     val cfg = UpdatesConfig(
       pin = List(aa0),
       allow = List(aa0),
       ignore = List(aa0),
-      limit = Some(PosInt(10)),
+      limit = Some(PosInt.unsafeFrom(10)),
       includeScala = Some(false),
       fileExtensions = Some(List(".txt", ".scala", ".sbt"))
     )
-    cfg |+| cfg shouldBe cfg
+    assertEquals(cfg |+| cfg, cfg)
 
-    cfg |+| emptyCfg shouldBe cfg
-    emptyCfg |+| cfg shouldBe cfg
+    assertEquals(cfg |+| emptyCfg, cfg)
+    assertEquals(emptyCfg |+| cfg, cfg)
 
     val cfg2 = UpdatesConfig(
       pin = List(ab0),
       allow = List(ab0),
       ignore = List(ab0),
-      limit = Some(PosInt(20)),
+      limit = Some(PosInt.unsafeFrom(20)),
       includeScala = Some(true),
       fileExtensions = Some(List(".sbt", ".scala"))
     )
 
-    cfg |+| cfg2 shouldBe UpdatesConfig(
-      pin = List(aa0, ab0),
-      allow = UpdatesConfig.nonExistingUpdatePattern,
-      ignore = List(aa0, ab0),
-      limit = Some(PosInt(10)),
-      includeScala = Some(false),
-      fileExtensions = Some(List(".scala", ".sbt"))
+    assertEquals(
+      cfg |+| cfg2,
+      UpdatesConfig(
+        pin = List(aa0, ab0),
+        allow = UpdatesConfig.nonExistingUpdatePattern,
+        ignore = List(aa0, ab0),
+        limit = Some(PosInt.unsafeFrom(10)),
+        includeScala = Some(false),
+        fileExtensions = Some(List(".scala", ".sbt"))
+      )
     )
 
-    cfg2 |+| cfg shouldBe UpdatesConfig(
-      pin = List(ab0, aa0),
-      allow = UpdatesConfig.nonExistingUpdatePattern,
-      ignore = List(ab0, aa0),
-      limit = Some(PosInt(20)),
-      includeScala = Some(true),
-      fileExtensions = Some(List(".sbt", ".scala"))
+    assertEquals(
+      cfg2 |+| cfg,
+      UpdatesConfig(
+        pin = List(ab0, aa0),
+        allow = UpdatesConfig.nonExistingUpdatePattern,
+        ignore = List(ab0, aa0),
+        limit = Some(PosInt.unsafeFrom(20)),
+        includeScala = Some(true),
+        fileExtensions = Some(List(".sbt", ".scala"))
+      )
     )
   }
 
   test("mergePin: basic checks") {
-    UpdatesConfig.mergePin(Nil, Nil) shouldBe Nil
-    UpdatesConfig.mergePin(List(a00), Nil) shouldBe List(a00)
-    UpdatesConfig.mergePin(Nil, List(b00)) shouldBe List(b00)
-    UpdatesConfig.mergePin(List(a00), List(b00)) shouldBe List(a00, b00)
+    assertEquals(UpdatesConfig.mergePin(Nil, Nil), Nil)
+    assertEquals(UpdatesConfig.mergePin(List(a00), Nil), List(a00))
+    assertEquals(UpdatesConfig.mergePin(Nil, List(b00)), List(b00))
+    assertEquals(UpdatesConfig.mergePin(List(a00), List(b00)), List(a00, b00))
 
-    UpdatesConfig.mergePin(List(aa1), List(aa1, ac3)) shouldBe List(aa1, ac3)
+    assertEquals(UpdatesConfig.mergePin(List(aa1), List(aa1, ac3)), List(aa1, ac3))
 
-    UpdatesConfig.mergePin(List(aa1), List(aa2)) shouldBe List(aa1)
-    UpdatesConfig.mergePin(List(aa2), List(aa1)) shouldBe List(aa2)
+    assertEquals(UpdatesConfig.mergePin(List(aa1), List(aa2)), List(aa1))
+    assertEquals(UpdatesConfig.mergePin(List(aa2), List(aa1)), List(aa2))
   }
 
   test("mergeAllow: basic checks") {
-    UpdatesConfig.mergeAllow(Nil, Nil) shouldBe Nil
-    UpdatesConfig.mergeAllow(List(a00), Nil) shouldBe List(a00)
-    UpdatesConfig.mergeAllow(Nil, List(a00)) shouldBe List(a00)
-
-    UpdatesConfig.mergeAllow(List(a00), List(a00)) shouldBe List(a00)
-    UpdatesConfig.mergeAllow(List(a00), List(b00)) shouldBe UpdatesConfig.nonExistingUpdatePattern
+    assertEquals(UpdatesConfig.mergeAllow(Nil, Nil), Nil)
+    assertEquals(UpdatesConfig.mergeAllow(List(a00), Nil), List(a00))
+    assertEquals(UpdatesConfig.mergeAllow(Nil, List(a00)), List(a00))
+
+    assertEquals(UpdatesConfig.mergeAllow(List(a00), List(a00)), List(a00))
+    assertEquals(
+      UpdatesConfig.mergeAllow(List(a00), List(b00)),
+      UpdatesConfig.nonExistingUpdatePattern
+    )
 
-    UpdatesConfig.mergeAllow(List(a00), List(aa1, ab0, ac3)) shouldBe List(aa1, ab0, ac3)
-    UpdatesConfig.mergeAllow(List(aa1, ab0, ac3), List(a00)) shouldBe List(aa1, ab0, ac3)
+    assertEquals(UpdatesConfig.mergeAllow(List(a00), List(aa1, ab0, ac3)), List(aa1, ab0, ac3))
+    assertEquals(UpdatesConfig.mergeAllow(List(aa1, ab0, ac3), List(a00)), List(aa1, ab0, ac3))
 
-    UpdatesConfig.mergeAllow(List(aa0), List(aa1, aa2)) shouldBe List(aa1, aa2)
-    UpdatesConfig.mergeAllow(List(aa1, aa2), List(aa0)) shouldBe List(aa1, aa2)
+    assertEquals(UpdatesConfig.mergeAllow(List(aa0), List(aa1, aa2)), List(aa1, aa2))
+    assertEquals(UpdatesConfig.mergeAllow(List(aa1, aa2), List(aa0)), List(aa1, aa2))
 
-    UpdatesConfig.mergeAllow(List(aa0), List(aa0, ab0)) shouldBe List(aa0)
-    UpdatesConfig.mergeAllow(List(aa0, ab0), List(aa0, ab0)) shouldBe List(aa0, ab0)
+    assertEquals(UpdatesConfig.mergeAllow(List(aa0), List(aa0, ab0)), List(aa0))
+    assertEquals(UpdatesConfig.mergeAllow(List(aa0, ab0), List(aa0, ab0)), List(aa0, ab0))
 
-    UpdatesConfig.mergeAllow(List(aa1), List(aa1)) shouldBe List(aa1)
-    UpdatesConfig.mergeAllow(List(aa1), List(aa2)) shouldBe UpdatesConfig.nonExistingUpdatePattern
-    UpdatesConfig.mergeAllow(List(aa1, ab0, ac0), List(aa2, ac0)) shouldBe List(ac0)
-    UpdatesConfig.mergeAllow(List(aa1, aa2), List(aa1, aa2)) shouldBe List(aa1, aa2)
-    UpdatesConfig.mergeAllow(List(aa1, aa2), List(aa1, ac3)) shouldBe List(aa1)
+    assertEquals(UpdatesConfig.mergeAllow(List(aa1), List(aa1)), List(aa1))
+    assertEquals(
+      UpdatesConfig.mergeAllow(List(aa1), List(aa2)),
+      UpdatesConfig.nonExistingUpdatePattern
+    )
+    assertEquals(UpdatesConfig.mergeAllow(List(aa1, ab0, ac0), List(aa2, ac0)), List(ac0))
+    assertEquals(UpdatesConfig.mergeAllow(List(aa1, aa2), List(aa1, aa2)), List(aa1, aa2))
+    assertEquals(UpdatesConfig.mergeAllow(List(aa1, aa2), List(aa1, ac3)), List(aa1))
   }
 
   test("mergeIgnore: basic checks") {
-    UpdatesConfig.mergeIgnore(Nil, Nil) shouldBe Nil
-    UpdatesConfig.mergeIgnore(List(a00), Nil) shouldBe List(a00)
-    UpdatesConfig.mergeIgnore(Nil, List(b00)) shouldBe List(b00)
-    UpdatesConfig.mergeIgnore(List(aa1, b00), List(aa1, aa2)) shouldBe List(aa1, b00, aa2)
+    assertEquals(UpdatesConfig.mergeIgnore(Nil, Nil), Nil)
+    assertEquals(UpdatesConfig.mergeIgnore(List(a00), Nil), List(a00))
+    assertEquals(UpdatesConfig.mergeIgnore(Nil, List(b00)), List(b00))
+    assertEquals(UpdatesConfig.mergeIgnore(List(aa1, b00), List(aa1, aa2)), List(aa1, b00, aa2))
   }
 
   test("mergeFileExtensions: basic checks") {
-    UpdatesConfig.mergeFileExtensions(None, None) shouldBe None
-    UpdatesConfig.mergeFileExtensions(None, Some(List("txt"))) shouldBe Some(List("txt"))
-    UpdatesConfig.mergeFileExtensions(Some(List("txt")), None) shouldBe Some(List("txt"))
-    UpdatesConfig.mergeFileExtensions(Some(List("txt")), Some(List("txt"))) shouldBe
+    assertEquals(UpdatesConfig.mergeFileExtensions(None, None), None)
+    assertEquals(UpdatesConfig.mergeFileExtensions(None, Some(List("txt"))), Some(List("txt")))
+    assertEquals(UpdatesConfig.mergeFileExtensions(Some(List("txt")), None), Some(List("txt")))
+    assertEquals(
+      UpdatesConfig.mergeFileExtensions(Some(List("txt")), Some(List("txt"))),
       Some(List("txt"))
-    UpdatesConfig.mergeFileExtensions(Some(List("a", "b", "c")), Some(List("b", "d"))) shouldBe
+    )
+    assertEquals(
+      UpdatesConfig.mergeFileExtensions(Some(List("a", "b", "c")), Some(List("b", "d"))),
       Some(List("b"))
-    UpdatesConfig.mergeFileExtensions(Some(List("a")), Some(List("b"))) shouldBe Some(List())
+    )
+    assertEquals(UpdatesConfig.mergeFileExtensions(Some(List("a")), Some(List("b"))), Some(List()))
   }
 
   test("fileExtensionsOrDefault: non-set != empty") {
-    UpdatesConfig(fileExtensions = None).fileExtensionsOrDefault shouldNot
-      be(UpdatesConfig(fileExtensions = Some(Nil)).fileExtensionsOrDefault)
+    assertNotEquals(
+      UpdatesConfig(fileExtensions = None).fileExtensionsOrDefault,
+      UpdatesConfig(fileExtensions = Some(Nil)).fileExtensionsOrDefault
+    )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationAlgTest.scala
index 1176eb95..cbfbc6ed 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationAlgTest.scala
@@ -1,17 +1,16 @@
 package org.scalasteward.core.scalafix
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.{GroupId, Update, Version}
 import org.scalasteward.core.mock.MockContext.migrationAlg
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class MigrationAlgTest extends AnyFunSuite with Matchers {
+class MigrationAlgTest extends FunSuite {
   test("findMigrations") {
     val update = Update.Single("org.typelevel" % "cats-core" % "2.1.0", Nel.of("2.2.0"))
     val migrations = migrationAlg.findMigrations(update)
-    migrations shouldBe List(
+    val expected = List(
       Migration(
         GroupId("org.typelevel"),
         Nel.of("cats-core"),
@@ -23,5 +22,6 @@ class MigrationAlgTest extends AnyFunSuite with Matchers {
         Some(Nel.of("-P:semanticdb:synthetics:on"))
       )
     )
+    assertEquals(migrations, expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationsLoaderTest.scala b/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationsLoaderTest.scala
index 52200fc6..e4f5b576 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationsLoaderTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationsLoaderTest.scala
@@ -1,5 +1,6 @@
 package org.scalasteward.core.scalafix
 
+import munit.FunSuite
 import org.http4s.Uri
 import org.scalasteward.core.application.Config.ScalafixCfg
 import org.scalasteward.core.data.{GroupId, Version}
@@ -8,10 +9,8 @@ import org.scalasteward.core.mock.MockContext._
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.scalafix.MigrationsLoaderTest.mockState
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class MigrationsLoaderTest extends AnyFunSuite with Matchers {
+class MigrationsLoaderTest extends FunSuite {
   val migrationsUri: Uri = Uri.unsafeFromString("/tmp/scala-steward/extra-migrations.conf")
   val migrationsContent: String =
     """|migrations = [
@@ -37,7 +36,7 @@ class MigrationsLoaderTest extends AnyFunSuite with Matchers {
       .loadAll(ScalafixCfg(Nil, disableDefaults = true))
       .runA(mockState)
       .unsafeRunSync()
-    migrations.size shouldBe 0
+    assertEquals(migrations.size, 0)
   }
 
   test("loadAll: without extra file, with defaults") {
@@ -45,7 +44,7 @@ class MigrationsLoaderTest extends AnyFunSuite with Matchers {
       .loadAll(ScalafixCfg(Nil, disableDefaults = false))
       .runA(mockState)
       .unsafeRunSync()
-    migrations.size should be > 0
+    assert(clue(migrations.size) > 0)
   }
 
   test("loadAll: with extra file, without defaults") {
@@ -54,7 +53,7 @@ class MigrationsLoaderTest extends AnyFunSuite with Matchers {
       .loadAll(ScalafixCfg(List(migrationsUri), disableDefaults = true))
       .runA(initialState)
       .unsafeRunSync()
-    migrations shouldBe List(migration)
+    assertEquals(migrations, List(migration))
   }
 
   test("loadAll: with extra file, with defaults") {
@@ -63,8 +62,8 @@ class MigrationsLoaderTest extends AnyFunSuite with Matchers {
       .loadAll(ScalafixCfg(List(migrationsUri), disableDefaults = false))
       .runA(initialState)
       .unsafeRunSync()
-    migrations.size should be > 1
-    migrations should contain(migration)
+    assert(clue(migrations.size) > 1)
+    assert(clue(migrations).contains(migration))
   }
 
   test("loadAll: malformed extra file") {
@@ -74,7 +73,7 @@ class MigrationsLoaderTest extends AnyFunSuite with Matchers {
       .runA(initialState)
       .attempt
       .unsafeRunSync()
-    migrations.isLeft shouldBe true
+    assert(migrations.isLeft)
   }
 }
 
diff --git a/modules/core/src/test/scala/org/scalasteward/core/scalafmt/ScalafmtAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/scalafmt/ScalafmtAlgTest.scala
index 4d5e54a7..660f3f7d 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/scalafmt/ScalafmtAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/scalafmt/ScalafmtAlgTest.scala
@@ -1,13 +1,12 @@
 package org.scalasteward.core.scalafmt
 
+import munit.FunSuite
 import org.scalasteward.core.data.Version
 import org.scalasteward.core.mock.MockContext._
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class ScalafmtAlgTest extends AnyFunSuite with Matchers {
+class ScalafmtAlgTest extends FunSuite {
   test("getScalafmtVersion on unquoted version") {
     val repo = Repo("fthomas", "scala-steward")
     val repoDir = config.workspace / repo.owner / repo.repo
@@ -19,11 +18,9 @@ class ScalafmtAlgTest extends AnyFunSuite with Matchers {
         |align.openParenCallSite = false
         |""".stripMargin
     )
-    val (state, maybeUpdate) =
+    val (state, maybeVersion) =
       scalafmtAlg.getScalafmtVersion(repo).run(initialState).unsafeRunSync()
-
-    maybeUpdate shouldBe Some(Version("2.0.0-RC8"))
-    state shouldBe MockState.empty.copy(
+    val expectedState = MockState.empty.copy(
       commands = Vector(List("read", s"$repoDir/.scalafmt.conf")),
       files = Map(
         scalafmtConf ->
@@ -33,6 +30,9 @@ class ScalafmtAlgTest extends AnyFunSuite with Matchers {
             |""".stripMargin
       )
     )
+
+    assertEquals(maybeVersion, Some(Version("2.0.0-RC8")))
+    assertEquals(state, expectedState)
   }
 
   test("getScalafmtVersion on quoted version") {
@@ -46,11 +46,7 @@ class ScalafmtAlgTest extends AnyFunSuite with Matchers {
         |align.openParenCallSite = false
         |""".stripMargin
     )
-    val (_, maybeUpdate) = scalafmtAlg.getScalafmtVersion(repo).run(initialState).unsafeRunSync()
-    maybeUpdate shouldBe Some(Version("2.0.0-RC8"))
-  }
-
-  test("editScalafmtConf") {
-    // Tested in EditAlgTest
+    val (_, maybeVersion) = scalafmtAlg.getScalafmtVersion(repo).run(initialState).unsafeRunSync()
+    assertEquals(maybeVersion, Some(Version("2.0.0-RC8")))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/update/ArtifactMigrationsTest.scala b/modules/core/src/test/scala/org/scalasteward/core/update/ArtifactMigrationsTest.scala
index 8eab2be3..34127684 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/update/ArtifactMigrationsTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/update/ArtifactMigrationsTest.scala
@@ -1,15 +1,14 @@
 package org.scalasteward.core.update
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.{ArtifactId, GroupId, Update}
 import org.scalasteward.core.mock.MockContext._
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.update.ArtifactMigrations.ArtifactChange
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class ArtifactMigrationsTest extends AnyFunSuite with Matchers {
+class ArtifactMigrationsTest extends FunSuite {
 
   val standardGroupMigrations = List(
     ArtifactChange(
@@ -43,12 +42,12 @@ class ArtifactMigrationsTest extends AnyFunSuite with Matchers {
 
   test("migrateArtifact: for groupId, returns empty if artifactIdAfter is not listed") {
     val original = "org.spire-math" % ArtifactId("UNKNOWN", "UNKNOWN_2.12") % "1.0.0"
-    ArtifactMigrations.migrateArtifact(original, standardGroupMigrations) shouldBe None
+    assertEquals(ArtifactMigrations.migrateArtifact(original, standardGroupMigrations), None)
   }
 
   test("migrateArtifact: for artifactId, returns empty if groupIdAfter is not listed") {
     val original = "UNKNOWN" % ArtifactId("artifact-before", "artifact-before_2.12") % "1.0.0"
-    ArtifactMigrations.migrateArtifact(original, standardArtifactMigrations) shouldBe None
+    assertEquals(ArtifactMigrations.migrateArtifact(original, standardArtifactMigrations), None)
   }
 
   test(
@@ -56,10 +55,10 @@ class ArtifactMigrationsTest extends AnyFunSuite with Matchers {
       "artifactIdBefore are not listed"
   ) {
     val original1 = "UNKNOWN" % ArtifactId("artifact-before", "artifact-before_2.12") % "1.0.0"
-    ArtifactMigrations.migrateArtifact(original1, standardBothMigrations) shouldBe None
+    assertEquals(ArtifactMigrations.migrateArtifact(original1, standardBothMigrations), None)
 
     val original2 = "org.before" % ArtifactId("UNKNOWN", "UNKNOWN_2.12") % "1.0.0"
-    ArtifactMigrations.migrateArtifact(original2, standardBothMigrations) shouldBe None
+    assertEquals(ArtifactMigrations.migrateArtifact(original2, standardBothMigrations), None)
   }
 
   test("migrateArtifact: for groupId, returns Update.Single for updating groupId") {
@@ -70,7 +69,10 @@ class ArtifactMigrationsTest extends AnyFunSuite with Matchers {
       Some(GroupId("org.typelevel")),
       Some("kind-projector")
     )
-    ArtifactMigrations.migrateArtifact(original, standardGroupMigrations) shouldBe Some(expected)
+    assertEquals(
+      ArtifactMigrations.migrateArtifact(original, standardGroupMigrations),
+      Some(expected)
+    )
   }
 
   test("migrateArtifact: for artifactId, returns Update.Single for updating artifactId") {
@@ -82,7 +84,10 @@ class ArtifactMigrationsTest extends AnyFunSuite with Matchers {
       Some(GroupId("com.nodifferent")),
       Some("artifact-after")
     )
-    ArtifactMigrations.migrateArtifact(original, standardArtifactMigrations) shouldBe Some(expected)
+    assertEquals(
+      ArtifactMigrations.migrateArtifact(original, standardArtifactMigrations),
+      Some(expected)
+    )
   }
 
   test(
@@ -96,7 +101,10 @@ class ArtifactMigrationsTest extends AnyFunSuite with Matchers {
       Some(GroupId("org.after")),
       Some("artifact-after")
     )
-    ArtifactMigrations.migrateArtifact(original, standardBothMigrations) shouldBe Some(expected)
+    assertEquals(
+      ArtifactMigrations.migrateArtifact(original, standardBothMigrations),
+      Some(expected)
+    )
   }
 
   test("findUpdate: newer groupId") {
@@ -108,10 +116,10 @@ class ArtifactMigrationsTest extends AnyFunSuite with Matchers {
       Some(GroupId("org.typelevel")),
       Some("kind-projector")
     )
-    val actual = updateAlg
+    val obtained = updateAlg
       .findUpdate(dependency.withMavenCentral, None)
       .runA(MockState.empty)
       .unsafeRunSync()
-    actual shouldBe Some(expected)
+    assertEquals(obtained, Some(expected))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/update/FilterAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/update/FilterAlgTest.scala
index 77232bd0..efb4d5b9 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/update/FilterAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/update/FilterAlgTest.scala
@@ -1,5 +1,6 @@
 package org.scalasteward.core.update
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.Update.Single
 import org.scalasteward.core.data.{ArtifactId, Dependency, GroupId}
@@ -8,30 +9,28 @@ import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.repoconfig.{RepoConfig, UpdatePattern, UpdatesConfig}
 import org.scalasteward.core.update.FilterAlg._
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class FilterAlgTest extends AnyFunSuite with Matchers {
+class FilterAlgTest extends FunSuite {
   private val config = RepoConfig.empty
 
   test("localFilter: SNAP -> SNAP") {
     val update = Single("org.scalatest" % "scalatest" % "3.0.8-SNAP2", Nel.of("3.0.8-SNAP10"))
-    localFilter(update, config) shouldBe Right(update)
+    assertEquals(localFilter(update, config), Right(update))
   }
 
   test("localFilter: RC -> SNAP") {
     val update = Single("org.scalatest" % "scalatest" % "3.0.8-RC2", Nel.of("3.1.0-SNAP10"))
-    localFilter(update, config) shouldBe Left(NoSuitableNextVersion(update))
+    assertEquals(localFilter(update, config), Left(NoSuitableNextVersion(update)))
   }
 
   test("localFilter: update without bad version") {
     val update = Single("com.jsuereth" % "sbt-pgp" % "1.1.0", Nel.of("1.1.2", "2.0.0"))
-    localFilter(update, config) shouldBe Right(update.copy(newerVersions = Nel.of("1.1.2")))
+    assertEquals(localFilter(update, config), Right(update.copy(newerVersions = Nel.of("1.1.2"))))
   }
 
   test("localFilter: update with bad version") {
     val update = Single("com.jsuereth" % "sbt-pgp" % "1.1.2-1", Nel.of("1.1.2", "2.0.0"))
-    localFilter(update, config) shouldBe Right(update.copy(newerVersions = Nel.of("2.0.0")))
+    assertEquals(localFilter(update, config), Right(update.copy(newerVersions = Nel.of("2.0.0"))))
   }
 
   test("localFilter: update with bad version 2") {
@@ -39,17 +38,20 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
       "net.sourceforge.plantuml" % "plantuml" % "1.2019.11",
       Nel.of("7726", "8020", "2017.09", "1.2019.12")
     )
-    localFilter(update, config) shouldBe Right(update.copy(newerVersions = Nel.of("1.2019.12")))
+    assertEquals(
+      localFilter(update, config),
+      Right(update.copy(newerVersions = Nel.of("1.2019.12")))
+    )
   }
 
   test("localFilter: update with only bad versions") {
     val update = Single("org.http4s" % "http4s-dsl" % "0.18.0", Nel.of("0.19.0"))
-    localFilter(update, config) shouldBe Left(BadVersions(update))
+    assertEquals(localFilter(update, config), Left(BadVersions(update)))
   }
 
   test("localFilter: update to pre-release of a different series") {
     val update = Single("com.jsuereth" % "sbt-pgp" % "1.1.2-1", Nel.of("2.0.1-M3"))
-    localFilter(update, config) shouldBe Left(NoSuitableNextVersion(update))
+    assertEquals(localFilter(update, config), Left(NoSuitableNextVersion(update)))
   }
 
   test("ignore update via config updates.ignore") {
@@ -63,12 +65,13 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
     val (state, filtered) =
       filterAlg.localFilterMany(config, List(update1, update2)).run(initialState).unsafeRunSync()
 
-    filtered shouldBe List(update1)
-    state shouldBe initialState.copy(
+    assertEquals(filtered, List(update1))
+    val expected = initialState.copy(
       logs = Vector(
         (None, "Ignore eu.timepit:refined : 0.8.0 -> 0.8.1 (reason: ignored by config)")
       )
     )
+    assertEquals(state, expected)
   }
 
   test("ignore update via config updates.pin") {
@@ -93,7 +96,7 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
       .runA(MockState.empty)
       .unsafeRunSync()
 
-    filtered shouldBe List(update2)
+    assertEquals(filtered, List(update2))
   }
 
   test("ignore update via config updates.allow") {
@@ -123,7 +126,7 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
       .runA(MockState.empty)
       .unsafeRunSync()
 
-    filtered shouldBe included
+    assertEquals(filtered, included)
   }
 
   test("ignore update via config updates.pin using suffix") {
@@ -145,7 +148,7 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
     )
 
     val filtered = localFilter(update, config)
-    filtered shouldBe Right(update.copy(newerVersions = Nel.of("7.3.0.jre8")))
+    assertEquals(filtered, Right(update.copy(newerVersions = Nel.of("7.3.0.jre8"))))
   }
 
   test("ignore update via config updates.ignore using suffix") {
@@ -167,7 +170,7 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
     )
 
     val filtered = localFilter(update, config)
-    filtered shouldBe Right(update.copy(newerVersions = Nel.of("7.3.0.jre8")))
+    assertEquals(filtered, Right(update.copy(newerVersions = Nel.of("7.3.0.jre8"))))
   }
 
   test("ignore update via config updates.pin using prefix and suffix") {
@@ -188,7 +191,7 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
       )
     )
 
-    localFilter(update, config) shouldBe Left(VersionPinnedByConfig(update))
+    assertEquals(localFilter(update, config), Left(VersionPinnedByConfig(update)))
   }
 
   test("isScalaDependency: true") {
@@ -197,13 +200,13 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
       ArtifactId("scala-compiler", "scala-compiler_2.12"),
       "2.12.10"
     )
-    isScalaDependency(dependency) shouldBe true
+    assert(isScalaDependency(dependency))
   }
 
   test("isScalaDependency: false") {
     val dependency =
       Dependency(GroupId("org.typelevel"), ArtifactId("cats-effect", "cats-effect_2.12"), "1.0.0")
-    isScalaDependency(dependency) shouldBe false
+    assert(!isScalaDependency(dependency))
   }
 
   test("isScalaDependencyIgnored: true") {
@@ -212,7 +215,7 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
       ArtifactId("scala-compiler", "scala-compiler_2.12"),
       "2.12.10"
     )
-    isScalaDependencyIgnored(dependency, ignoreScalaDependency = true) shouldBe true
+    assert(isScalaDependencyIgnored(dependency, ignoreScalaDependency = true))
   }
 
   test("isScalaDependencyIgnored: false") {
@@ -221,20 +224,22 @@ class FilterAlgTest extends AnyFunSuite with Matchers {
       ArtifactId("scala-compiler", "scala-compiler_2.12"),
       "2.12.10"
     )
-    isScalaDependencyIgnored(dependency, ignoreScalaDependency = false) shouldBe false
+    assert(!isScalaDependencyIgnored(dependency, ignoreScalaDependency = false))
   }
 
   test("isDependencyConfigurationIgnored: false") {
     val dependency =
       Dependency(GroupId("org.typelevel"), ArtifactId("cats-effect", "cats-effect_2.12"), "1.0.0")
-    isDependencyConfigurationIgnored(dependency.copy(configurations = Some("foo"))) shouldBe false
+    assert(!isDependencyConfigurationIgnored(dependency.copy(configurations = Some("foo"))))
   }
 
   test("isDependencyConfigurationIgnored: true") {
     val dependency =
       Dependency(GroupId("org.typelevel"), ArtifactId("cats-effect", "cats-effect_2.12"), "1.0.0")
-    isDependencyConfigurationIgnored(
-      dependency.copy(configurations = Some("scalafmt"))
-    ) shouldBe true
+    assert(
+      isDependencyConfigurationIgnored(
+        dependency.copy(configurations = Some("scalafmt"))
+      )
+    )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/update/PruningAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/update/PruningAlgTest.scala
index 2be34996..292499f6 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/update/PruningAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/update/PruningAlgTest.scala
@@ -1,14 +1,13 @@
 package org.scalasteward.core.update
 
+import io.circe.parser.decode
+import munit.FunSuite
 import org.scalasteward.core.mock.MockContext._
 import org.scalasteward.core.mock.MockState
 import org.scalasteward.core.repocache.RepoCache
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import io.circe.parser.decode
-import org.scalatest.matchers.should.Matchers
 
-class PruningAlgTest extends AnyFunSuite with Matchers {
+class PruningAlgTest extends FunSuite {
   private val defaultConf = config.defaultRepoConfigFile.map(_.toString).getOrElse("")
 
   test("needsAttention") {
@@ -58,8 +57,7 @@ class PruningAlgTest extends AnyFunSuite with Matchers {
     val initial = MockState.empty
       .add(pullRequestsFile, pullRequestsContent)
     val state = pruningAlg.needsAttention(repo, repoCache).runS(initial).unsafeRunSync()
-
-    state shouldBe initial.copy(
+    val expected = initial.copy(
       commands = Vector(
         List("read", defaultConf),
         List("read", pullRequestsFile.toString)
@@ -70,6 +68,7 @@ class PruningAlgTest extends AnyFunSuite with Matchers {
         (None, "fthomas/scalafix-test is up-to-date")
       )
     )
+    assertEquals(state, expected)
   }
 
   test("needsAttention: 0 updates when includeScala not specified in repo config") {
@@ -163,8 +162,7 @@ class PruningAlgTest extends AnyFunSuite with Matchers {
       .add(pullRequestsFile, pullRequestsContent)
       .add(versionsFile, versionsContent)
     val state = pruningAlg.needsAttention(repo, repoCache).runS(initial).unsafeRunSync()
-
-    state shouldBe initial.copy(
+    val expected = initial.copy(
       commands = Vector(
         List("read", defaultConf),
         List("read", pullRequestsFile.toString)
@@ -175,6 +173,7 @@ class PruningAlgTest extends AnyFunSuite with Matchers {
         (None, "fthomas/scalafix-test is up-to-date")
       )
     )
+    assertEquals(state, expected)
   }
 
   test("needsAttention: update scala-library when includeScala=true in repo config") {
@@ -278,8 +277,7 @@ class PruningAlgTest extends AnyFunSuite with Matchers {
       .add(pullRequestsFile, pullRequestsContent)
       .add(versionsFile, versionsContent)
     val state = pruningAlg.needsAttention(repo, repoCache).runS(initial).unsafeRunSync()
-
-    state shouldBe initial.copy(
+    val expected = initial.copy(
       commands = Vector(
         List("read", defaultConf),
         List("read", versionsFile.toString),
@@ -297,5 +295,6 @@ class PruningAlgTest extends AnyFunSuite with Matchers {
         )
       )
     )
+    assertEquals(state, expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/update/UpdateAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/update/UpdateAlgTest.scala
index 757e270b..b9e9bfef 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/update/UpdateAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/update/UpdateAlgTest.scala
@@ -1,13 +1,11 @@
 package org.scalasteward.core.update
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.{ArtifactId, Update}
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-
-class UpdateAlgTest extends AnyFunSuite with Matchers {
 
+class UpdateAlgTest extends FunSuite {
   test("isUpdateFor") {
     val dependency = "io.circe" % ArtifactId("circe-refined", "circe-refined_2.12") % "0.11.2"
     val update = Update.Group(
@@ -20,6 +18,6 @@ class UpdateAlgTest extends AnyFunSuite with Matchers {
       ),
       Nel.of("0.12.3")
     )
-    UpdateAlg.isUpdateFor(update, dependency) shouldBe true
+    assert(UpdateAlg.isUpdateFor(update, dependency))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/update/showTest.scala b/modules/core/src/test/scala/org/scalasteward/core/update/showTest.scala
index fd3f3861..b12505ef 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/update/showTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/update/showTest.scala
@@ -1,13 +1,12 @@
 package org.scalasteward.core.update
 
+import munit.FunSuite
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.data.ArtifactId
 import org.scalasteward.core.data.Update.{Group, Single}
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class showTest extends AnyFunSuite with Matchers {
+class showTest extends FunSuite {
   test("oneLiner: cats-core") {
     val update = Single(
       "org.typelevel" % Nel.of(
@@ -16,33 +15,33 @@ class showTest extends AnyFunSuite with Matchers {
       ) % "0.9.0",
       Nel.one("1.0.0")
     )
-    show.oneLiner(update) shouldBe "cats-core"
+    assertEquals(show.oneLiner(update), "cats-core")
   }
 
   test("oneLiner: fs2-core") {
     val update = Single("co.fs2" % "fs2-core" % "0.9.7", Nel.one("1.0.0"))
-    show.oneLiner(update) shouldBe "fs2-core"
+    assertEquals(show.oneLiner(update), "fs2-core")
   }
 
   test("oneLiner: monix") {
     val update = Single("io.monix" % "monix" % "2.3.3", Nel.one("3.0.0"))
-    show.oneLiner(update) shouldBe "monix"
+    assertEquals(show.oneLiner(update), "monix")
   }
 
   test("oneLiner: sttp:core") {
     val update = Single("com.softwaremill.sttp" % "core" % "1.3.3", Nel.one("1.3.5"))
-    show.oneLiner(update) shouldBe "sttp:core"
+    assertEquals(show.oneLiner(update), "sttp:core")
   }
 
   test("oneLiner: typesafe:config") {
     val update = Single("com.typesafe" % "config" % "1.3.0", Nel.one("1.3.3"))
-    show.oneLiner(update) shouldBe "typesafe:config"
+    assertEquals(show.oneLiner(update), "typesafe:config")
   }
 
   test("oneLiner: single update with very long artifactId") {
     val artifactId = "1234567890" * 5
     val update = Single("org.example" % artifactId % "1.0.0", Nel.one("2.0.0"))
-    show.oneLiner(update) shouldBe artifactId
+    assertEquals(show.oneLiner(update), artifactId)
   }
 
   test("oneLiner: group update with two artifacts") {
@@ -52,7 +51,7 @@ class showTest extends AnyFunSuite with Matchers {
         Nel.one("1.0.0")
       )
     val expected = "cats-core, cats-free"
-    show.oneLiner(update) shouldBe expected
+    assertEquals(show.oneLiner(update), expected)
   }
 
   test("oneLiner: group update with four artifacts") {
@@ -61,14 +60,14 @@ class showTest extends AnyFunSuite with Matchers {
       Nel.one("1.0.0")
     )
     val expected = "cats-core, cats-free, cats-laws, ..."
-    show.oneLiner(update) shouldBe expected
+    assertEquals(show.oneLiner(update), expected)
   }
 
   test("oneLiner: group update with four short artifacts") {
     val update =
       Group("group" % Nel.of("data", "free", "laws", "macros") % "0.9.0", Nel.one("1.0.0"))
     val expected = "data, free, laws, macros"
-    show.oneLiner(update) shouldBe expected
+    assertEquals(show.oneLiner(update), expected)
   }
 
   test("oneLiner: group update where one artifactId is a common suffix") {
@@ -77,6 +76,6 @@ class showTest extends AnyFunSuite with Matchers {
       Nel.one("1.3.5")
     )
     val expected = "sttp:circe, sttp:core, ..."
-    show.oneLiner(update) shouldBe expected
+    assertEquals(show.oneLiner(update), expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/util/ChangeTest.scala b/modules/core/src/test/scala/org/scalasteward/core/util/ChangeTest.scala
index 792de0c0..f47121c6 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/util/ChangeTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/util/ChangeTest.scala
@@ -1,11 +1,10 @@
 package org.scalasteward.core.util
+
 import cats.kernel.laws.discipline.MonoidTests
+import munit.DisciplineSuite
 import org.scalasteward.core.TestInstances._
 import org.scalasteward.core.util.Change._
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-import org.typelevel.discipline.scalatest.FunSuiteDiscipline
 
-class ChangeTest extends AnyFunSuite with FunSuiteDiscipline with ScalaCheckPropertyChecks {
+class ChangeTest extends DisciplineSuite {
   checkAll("Monoid[Change[T]]", MonoidTests[Change[String]].monoid)
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/util/dateTimeTest.scala b/modules/core/src/test/scala/org/scalasteward/core/util/dateTimeTest.scala
index 1e18acab..e4f5cdcf 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/util/dateTimeTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/util/dateTimeTest.scala
@@ -1,23 +1,21 @@
 package org.scalasteward.core.util
 
 import cats.syntax.all._
+import munit.ScalaCheckSuite
+import org.scalacheck.Prop._
 import org.scalasteward.core.util.dateTime._
-import org.scalatest.Assertion
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
 import scala.concurrent.duration._
 
-class dateTimeTest extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {
-  def approxEq(x: FiniteDuration, y: FiniteDuration): Assertion = {
+class dateTimeTest extends ScalaCheckSuite {
+  def approxEq(x: FiniteDuration, y: FiniteDuration): Unit = {
     val eps = 1.microsecond
-    (x - y).toNanos.abs should be <= eps.toNanos
+    assert(clue((x - y).toNanos.abs) <= clue(eps.toNanos))
   }
 
-  def parseFiniteDurationRoundTrips(fd: FiniteDuration): Assertion =
+  def parseFiniteDurationRoundTrips(fd: FiniteDuration): Unit =
     parseFiniteDuration(fd.toString).fold(t => throw t, approxEq(_, fd))
 
-  test("parseFiniteDuration") {
+  property("parseFiniteDuration") {
     forAll((d: FiniteDuration) => parseFiniteDurationRoundTrips(d))
   }
 
@@ -27,18 +25,18 @@ class dateTimeTest extends AnyFunSuite with Matchers with ScalaCheckPropertyChec
 
   test("showDuration: example 1") {
     val d = 2.days + 20.hours + 37.minutes + 3.seconds + 586.millis + 491.micros + 264.nanos
-    showDuration(d) shouldBe "2d 20h 37m 3s 586ms 491µs 264ns"
+    assertEquals(showDuration(d), "2d 20h 37m 3s 586ms 491µs 264ns")
   }
 
   test("showDuration: example 2") {
-    showDuration(60.minutes + 30.seconds + 1000.millis) shouldBe "1h 31s"
+    assertEquals(showDuration(60.minutes + 30.seconds + 1000.millis), "1h 31s")
   }
 
   test("showDuration: example 3") {
-    showDuration(23.hours + 59.minutes + 59.seconds + 1000.millis) shouldBe "1d"
+    assertEquals(showDuration(23.hours + 59.minutes + 59.seconds + 1000.millis), "1d")
   }
 
-  test("splitDuration and combineAll is identity") {
+  property("splitDuration and combineAll is identity") {
     forAll((d: FiniteDuration) => splitDuration(d).combineAll.eqv(d))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/util/loggerTest.scala b/modules/core/src/test/scala/org/scalasteward/core/util/loggerTest.scala
index c9d8d952..df1cbd28 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/util/loggerTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/util/loggerTest.scala
@@ -1,13 +1,12 @@
 package org.scalasteward.core.util
 
 import cats.effect.Sync
+import munit.FunSuite
 import org.scalasteward.core.mock.MockContext._
 import org.scalasteward.core.mock.{MockEff, MockState}
 import org.scalasteward.core.util.logger.LoggerOps
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class loggerTest extends AnyFunSuite with Matchers {
+class loggerTest extends FunSuite {
   test("attemptLog") {
     final case class Err(msg: String) extends Throwable(msg)
     val err = Err("hmm?")
@@ -16,7 +15,7 @@ class loggerTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty)
       .unsafeRunSync()
 
-    state.logs shouldBe Vector((None, "run"), (Some(err), "run failed"))
+    assertEquals(state.logs, Vector((None, "run"), (Some(err), "run failed")))
   }
 
   test("infoTimed") {
@@ -25,6 +24,6 @@ class loggerTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty)
       .unsafeRunSync()
 
-    state.logs shouldBe Vector((None, "inner"), (None, "timed"))
+    assertEquals(state.logs, Vector((None, "inner"), (None, "timed")))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/util/stringTest.scala b/modules/core/src/test/scala/org/scalasteward/core/util/stringTest.scala
index e95465a8..7cceee93 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/util/stringTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/util/stringTest.scala
@@ -1,34 +1,23 @@
 package org.scalasteward.core.util
 
+import munit.ScalaCheckSuite
 import org.scalacheck.Gen
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
+import org.scalacheck.Prop._
 
-class stringTest extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {
-  test("splitBetweenLowerAndUpperChars(s).mkString == s") {
+class stringTest extends ScalaCheckSuite {
+  property("splitBetweenLowerAndUpperChars(s).mkString == s") {
     forAll(Gen.asciiStr) { s: String =>
-      string.splitBetweenLowerAndUpperChars(s).mkString shouldBe s
-    }
-  }
-
-  test(
-    "splitBetweenLowerAndUpperChars: substrings end with lower case char or all are upper case"
-  ) {
-    forAll(Gen.asciiStr) { s: String =>
-      string
-        .splitBetweenLowerAndUpperChars(s)
-        .forall(sub => sub.matches(".*\\p{javaLowerCase}") || sub.matches("\\p{javaUpperCase}*"))
+      assertEquals(string.splitBetweenLowerAndUpperChars(s).mkString, s)
     }
   }
 
   test("splitBetweenLowerAndUpperChars: examples") {
-    string.splitBetweenLowerAndUpperChars("") shouldBe List("")
-    string.splitBetweenLowerAndUpperChars("a") shouldBe List("a")
-    string.splitBetweenLowerAndUpperChars("A") shouldBe List("A")
-    string.splitBetweenLowerAndUpperChars("aa") shouldBe List("aa")
-    string.splitBetweenLowerAndUpperChars("AA") shouldBe List("AA")
-    string.splitBetweenLowerAndUpperChars("aA") shouldBe List("a", "A")
-    string.splitBetweenLowerAndUpperChars("aAbB") shouldBe List("a", "Ab", "B")
+    assertEquals(string.splitBetweenLowerAndUpperChars(""), List(""))
+    assertEquals(string.splitBetweenLowerAndUpperChars("a"), List("a"))
+    assertEquals(string.splitBetweenLowerAndUpperChars("A"), List("A"))
+    assertEquals(string.splitBetweenLowerAndUpperChars("aa"), List("aa"))
+    assertEquals(string.splitBetweenLowerAndUpperChars("AA"), List("AA"))
+    assertEquals(string.splitBetweenLowerAndUpperChars("aA"), List("a", "A"))
+    assertEquals(string.splitBetweenLowerAndUpperChars("aAbB"), List("a", "Ab", "B"))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/util/uriTest.scala b/modules/core/src/test/scala/org/scalasteward/core/util/uriTest.scala
index bb23f7e3..bf3136bf 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/util/uriTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/util/uriTest.scala
@@ -1,14 +1,15 @@
 package org.scalasteward.core.util
 
+import munit.FunSuite
 import org.http4s.Uri.UserInfo
 import org.http4s.syntax.literals._
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class uriTest extends AnyFunSuite with Matchers {
+class uriTest extends FunSuite {
   test("withUserInfo") {
     val url = uri"https://api.github.com/repos/"
-    uri.withUserInfo.set(UserInfo("user", Some("pass")))(url).toString shouldBe
+    assertEquals(
+      uri.withUserInfo.set(UserInfo("user", Some("pass")))(url).toString,
       "https://user:pass@api.github.com/repos/"
+    )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/util/utilTest.scala b/modules/core/src/test/scala/org/scalasteward/core/util/utilTest.scala
index 5f643ceb..e1d6b10d 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/util/utilTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/util/utilTest.scala
@@ -1,39 +1,38 @@
 package org.scalasteward.core.util
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
+
+import munit.FunSuite
 import scala.collection.mutable.ListBuffer
 
-class utilTest extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {
+class utilTest extends FunSuite {
   test("appendBounded") {
     val lb = new ListBuffer[Int]
     lb.appendAll(List(1, 2, 3))
 
     appendBounded(lb, 4, 4)
-    lb.toList shouldBe List(1, 2, 3, 4)
+    assertEquals(lb.toList, List(1, 2, 3, 4))
 
     appendBounded(lb, 5, 4)
-    lb.toList shouldBe List(3, 4, 5)
+    assertEquals(lb.toList, List(3, 4, 5))
 
     appendBounded(lb, 6, 4)
-    lb.toList shouldBe List(3, 4, 5, 6)
+    assertEquals(lb.toList, List(3, 4, 5, 6))
 
     appendBounded(lb, 7, 6)
-    lb.toList shouldBe List(3, 4, 5, 6, 7)
+    assertEquals(lb.toList, List(3, 4, 5, 6, 7))
 
     appendBounded(lb, 8, 6)
-    lb.toList shouldBe List(3, 4, 5, 6, 7, 8)
+    assertEquals(lb.toList, List(3, 4, 5, 6, 7, 8))
 
     appendBounded(lb, 9, 6)
-    lb.toList shouldBe List(6, 7, 8, 9)
+    assertEquals(lb.toList, List(6, 7, 8, 9))
   }
 
   test("bindUntilTrue: empty list") {
-    bindUntilTrue(List.empty[Option[Boolean]]) shouldBe Some(false)
+    assertEquals(bindUntilTrue(List.empty[Option[Boolean]]), Some(false))
   }
 
   test("intersects") {
-    intersects(List(1, 3, 5), Vector(2, 4, 6)) shouldBe false
-    intersects(List(1, 3, 5), Vector(2, 3, 6)) shouldBe true
+    assert(!intersects(List(1, 3, 5), Vector(2, 4, 6)))
+    assert(intersects(List(1, 3, 5), Vector(2, 3, 6)))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala
index 75a66a03..40a7d1a0 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala
@@ -1,6 +1,7 @@
 package org.scalasteward.core.vcs
 
 import cats.effect.IO
+import munit.FunSuite
 import org.http4s.HttpRoutes
 import org.http4s.client.Client
 import org.http4s.dsl.io._
@@ -11,10 +12,8 @@ import org.scalasteward.core.application.SupportedVCS
 import org.scalasteward.core.data.{ReleaseRelatedUrl, Update}
 import org.scalasteward.core.mock.MockContext
 import org.scalasteward.core.util.{HttpExistenceClient, Nel}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class VCSExtraAlgTest extends AnyFunSuite with Matchers {
+class VCSExtraAlgTest extends FunSuite {
   val routes: HttpRoutes[IO] =
     HttpRoutes.of[IO] {
       case HEAD -> Root / "foo" / "bar" / "compare" / "v0.1.0...v0.2.0" => Ok("exist")
@@ -26,26 +25,35 @@ class VCSExtraAlgTest extends AnyFunSuite with Matchers {
   implicit val httpExistenceClient: HttpExistenceClient[IO] =
     HttpExistenceClient.create[IO](MockContext.config).allocated.map(_._1).unsafeRunSync()
 
-  val updateFoo = Update.Single("com.example" % "foo" % "0.1.0", Nel.of("0.2.0"))
-  val updateBar = Update.Single("com.example" % "bar" % "0.1.0", Nel.of("0.2.0"))
-  val updateBuz = Update.Single("com.example" % "buz" % "0.1.0", Nel.of("0.2.0"))
+  private val updateFoo = Update.Single("com.example" % "foo" % "0.1.0", Nel.of("0.2.0"))
+  private val updateBar = Update.Single("com.example" % "bar" % "0.1.0", Nel.of("0.2.0"))
+  private val updateBuz = Update.Single("com.example" % "buz" % "0.1.0", Nel.of("0.2.0"))
 
   test("getBranchCompareUrl: std vsc") {
     val vcsExtraAlg = VCSExtraAlg.create[IO](MockContext.config)
 
-    vcsExtraAlg
-      .getReleaseRelatedUrls(uri"https://github.com/foo/foo", updateFoo)
-      .unsafeRunSync() shouldBe List.empty
+    assertEquals(
+      vcsExtraAlg
+        .getReleaseRelatedUrls(uri"https://github.com/foo/foo", updateFoo)
+        .unsafeRunSync(),
+      List.empty
+    )
 
-    vcsExtraAlg
-      .getReleaseRelatedUrls(uri"https://github.com/foo/bar", updateBar)
-      .unsafeRunSync() shouldBe List(
-      ReleaseRelatedUrl.VersionDiff(uri"https://github.com/foo/bar/compare/v0.1.0...v0.2.0")
+    assertEquals(
+      vcsExtraAlg
+        .getReleaseRelatedUrls(uri"https://github.com/foo/bar", updateBar)
+        .unsafeRunSync(),
+      List(
+        ReleaseRelatedUrl.VersionDiff(uri"https://github.com/foo/bar/compare/v0.1.0...v0.2.0")
+      )
     )
 
-    vcsExtraAlg
-      .getReleaseRelatedUrls(uri"https://github.com/foo/buz", updateBuz)
-      .unsafeRunSync() shouldBe List.empty
+    assertEquals(
+      vcsExtraAlg
+        .getReleaseRelatedUrls(uri"https://github.com/foo/buz", updateBuz)
+        .unsafeRunSync(),
+      List.empty
+    )
   }
 
   test("getBranchCompareUrl: github on prem") {
@@ -55,18 +63,29 @@ class VCSExtraAlgTest extends AnyFunSuite with Matchers {
     )
     val githubOnPremVcsExtraAlg = VCSExtraAlg.create[IO](config)
 
-    githubOnPremVcsExtraAlg
-      .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/foo", updateFoo)
-      .unsafeRunSync() shouldBe List.empty
+    assertEquals(
+      githubOnPremVcsExtraAlg
+        .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/foo", updateFoo)
+        .unsafeRunSync(),
+      List.empty
+    )
 
-    githubOnPremVcsExtraAlg
-      .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/bar", updateBar)
-      .unsafeRunSync() shouldBe List(
-      ReleaseRelatedUrl.VersionDiff(uri"https://github.on-prem.com/foo/bar/compare/v0.1.0...v0.2.0")
+    assertEquals(
+      githubOnPremVcsExtraAlg
+        .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/bar", updateBar)
+        .unsafeRunSync(),
+      List(
+        ReleaseRelatedUrl.VersionDiff(
+          uri"https://github.on-prem.com/foo/bar/compare/v0.1.0...v0.2.0"
+        )
+      )
     )
 
-    githubOnPremVcsExtraAlg
-      .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/buz", updateFoo)
-      .unsafeRunSync() shouldBe List.empty
+    assertEquals(
+      githubOnPremVcsExtraAlg
+        .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/buz", updateFoo)
+        .unsafeRunSync(),
+      List.empty
+    )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSPackageTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSPackageTest.scala
index 5e3ad52a..99ccdb02 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSPackageTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSPackageTest.scala
@@ -1,5 +1,6 @@
 package org.scalasteward.core.vcs
 
+import munit.FunSuite
 import org.http4s.syntax.literals._
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.application.SupportedVCS
@@ -7,10 +8,8 @@ import org.scalasteward.core.application.SupportedVCS.{GitHub, GitLab}
 import org.scalasteward.core.data.Update
 import org.scalasteward.core.util.Nel
 import org.scalasteward.core.vcs.data.{PullRequestNumber, Repo}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class VCSPackageTest extends AnyFunSuite with Matchers {
+class VCSPackageTest extends FunSuite {
   test(s"extractPullRequestNumberFrom: valid") {
     val urls = List(
       uri"https://api.bitbucket.org/2.0/repositories/fthomas/base.g8/pullrequests/13",
@@ -18,7 +17,7 @@ class VCSPackageTest extends AnyFunSuite with Matchers {
       uri"https://gitlab.com/inkscape/inkscape/-/merge_requests/13"
     )
     urls.foreach { uri =>
-      extractPullRequestNumberFrom(uri) shouldBe Some(PullRequestNumber(13))
+      assertEquals(extractPullRequestNumberFrom(uri), Some(PullRequestNumber(13)))
     }
   }
 
@@ -29,7 +28,7 @@ class VCSPackageTest extends AnyFunSuite with Matchers {
       uri"https://gitlab.com/inkscape/inkscape/-/merge_requests/"
     )
     urls.foreach { uri =>
-      extractPullRequestNumberFrom(uri) shouldBe None
+      assertEquals(extractPullRequestNumberFrom(uri), None)
     }
   }
 
@@ -38,74 +37,109 @@ class VCSPackageTest extends AnyFunSuite with Matchers {
     Update.Single("ch.qos.logback" % "logback-classic" % "1.2.0", Nel.of("1.2.3"))
 
   test("listingBranch") {
-    listingBranch(GitHub, repo, update) shouldBe "foo/bar:update/logback-classic-1.2.3"
-    listingBranch(GitLab, repo, update) shouldBe "update/logback-classic-1.2.3"
+    assertEquals(listingBranch(GitHub, repo, update), "foo/bar:update/logback-classic-1.2.3")
+    assertEquals(listingBranch(GitLab, repo, update), "update/logback-classic-1.2.3")
   }
 
   test("createBranch") {
-    createBranch(GitHub, repo, update) shouldBe "foo:update/logback-classic-1.2.3"
-    createBranch(GitLab, repo, update) shouldBe "update/logback-classic-1.2.3"
+    assertEquals(createBranch(GitHub, repo, update), "foo:update/logback-classic-1.2.3")
+    assertEquals(createBranch(GitLab, repo, update), "update/logback-classic-1.2.3")
   }
 
   test("possibleCompareUrls") {
     val onPremVCS = "https://github.onprem.io/"
     val onPremVCSUri = uri"https://github.onprem.io/"
 
-    possibleCompareUrls(SupportedVCS.GitHub, onPremVCSUri, uri"https://github.com/foo/bar", update)
-      .map(_.url.renderString) shouldBe List(
-      "https://github.com/foo/bar/compare/v1.2.0...v1.2.3",
-      "https://github.com/foo/bar/compare/1.2.0...1.2.3",
-      "https://github.com/foo/bar/compare/release-1.2.0...release-1.2.3"
+    assertEquals(
+      possibleCompareUrls(
+        SupportedVCS.GitHub,
+        onPremVCSUri,
+        uri"https://github.com/foo/bar",
+        update
+      ).map(_.url.renderString),
+      List(
+        "https://github.com/foo/bar/compare/v1.2.0...v1.2.3",
+        "https://github.com/foo/bar/compare/1.2.0...1.2.3",
+        "https://github.com/foo/bar/compare/release-1.2.0...release-1.2.3"
+      )
     )
+
     // should canonicalize (drop last slash)
-    possibleCompareUrls(SupportedVCS.GitHub, onPremVCSUri, uri"https://github.com/foo/bar/", update)
-      .map(_.url.renderString) shouldBe List(
-      "https://github.com/foo/bar/compare/v1.2.0...v1.2.3",
-      "https://github.com/foo/bar/compare/1.2.0...1.2.3",
-      "https://github.com/foo/bar/compare/release-1.2.0...release-1.2.3"
+    assertEquals(
+      possibleCompareUrls(
+        SupportedVCS.GitHub,
+        onPremVCSUri,
+        uri"https://github.com/foo/bar/",
+        update
+      ).map(_.url.renderString),
+      List(
+        "https://github.com/foo/bar/compare/v1.2.0...v1.2.3",
+        "https://github.com/foo/bar/compare/1.2.0...1.2.3",
+        "https://github.com/foo/bar/compare/release-1.2.0...release-1.2.3"
+      )
     )
 
-    possibleCompareUrls(SupportedVCS.GitHub, onPremVCSUri, uri"https://gitlab.com/foo/bar", update)
-      .map(_.url.renderString) shouldBe List(
-      "https://gitlab.com/foo/bar/compare/v1.2.0...v1.2.3",
-      "https://gitlab.com/foo/bar/compare/1.2.0...1.2.3",
-      "https://gitlab.com/foo/bar/compare/release-1.2.0...release-1.2.3"
-    )
-    possibleCompareUrls(
-      SupportedVCS.GitHub,
-      onPremVCSUri,
-      uri"https://bitbucket.org/foo/bar",
-      update
+    assertEquals(
+      possibleCompareUrls(
+        SupportedVCS.GitHub,
+        onPremVCSUri,
+        uri"https://gitlab.com/foo/bar",
+        update
+      ).map(_.url.renderString),
+      List(
+        "https://gitlab.com/foo/bar/compare/v1.2.0...v1.2.3",
+        "https://gitlab.com/foo/bar/compare/1.2.0...1.2.3",
+        "https://gitlab.com/foo/bar/compare/release-1.2.0...release-1.2.3"
+      )
     )
-      .map(_.url.renderString) shouldBe List(
-      "https://bitbucket.org/foo/bar/compare/v1.2.3..v1.2.0#diff",
-      "https://bitbucket.org/foo/bar/compare/1.2.3..1.2.0#diff",
-      "https://bitbucket.org/foo/bar/compare/release-1.2.3..release-1.2.0#diff"
+
+    assertEquals(
+      possibleCompareUrls(
+        SupportedVCS.GitHub,
+        onPremVCSUri,
+        uri"https://bitbucket.org/foo/bar",
+        update
+      ).map(_.url.renderString),
+      List(
+        "https://bitbucket.org/foo/bar/compare/v1.2.3..v1.2.0#diff",
+        "https://bitbucket.org/foo/bar/compare/1.2.3..1.2.0#diff",
+        "https://bitbucket.org/foo/bar/compare/release-1.2.3..release-1.2.0#diff"
+      )
     )
 
-    possibleCompareUrls(
-      SupportedVCS.GitHub,
-      onPremVCSUri,
-      uri"https://scalacenter.github.io/scalafix/",
-      update
-    ) shouldBe List.empty
+    assertEquals(
+      possibleCompareUrls(
+        SupportedVCS.GitHub,
+        onPremVCSUri,
+        uri"https://scalacenter.github.io/scalafix/",
+        update
+      ),
+      List.empty
+    )
 
-    possibleCompareUrls(SupportedVCS.GitHub, onPremVCSUri, onPremVCSUri.addPath("/foo/bar"), update)
-      .map(_.url.renderString) shouldBe List(
-      s"${onPremVCS}foo/bar/compare/v1.2.0...v1.2.3",
-      s"${onPremVCS}foo/bar/compare/1.2.0...1.2.3",
-      s"${onPremVCS}foo/bar/compare/release-1.2.0...release-1.2.3"
+    assertEquals(
+      possibleCompareUrls(
+        SupportedVCS.GitHub,
+        onPremVCSUri,
+        onPremVCSUri.addPath("/foo/bar"),
+        update
+      ).map(_.url.renderString),
+      List(
+        s"${onPremVCS}foo/bar/compare/v1.2.0...v1.2.3",
+        s"${onPremVCS}foo/bar/compare/1.2.0...1.2.3",
+        s"${onPremVCS}foo/bar/compare/release-1.2.0...release-1.2.3"
+      )
     )
   }
 
   test("possibleChangelogUrls: github.com") {
-    possibleReleaseRelatedUrls(
+    val obtained = possibleReleaseRelatedUrls(
       SupportedVCS.GitHub,
       uri"https://github.com",
       uri"https://github.com/foo/bar",
       update
-    )
-      .map(_.url.renderString) shouldBe List(
+    ).map(_.url.renderString)
+    val expected = List(
       "https://github.com/foo/bar/releases/tag/v1.2.3",
       "https://github.com/foo/bar/releases/tag/1.2.3",
       "https://github.com/foo/bar/releases/tag/release-1.2.3",
@@ -137,70 +171,71 @@ class VCSPackageTest extends AnyFunSuite with Matchers {
       "https://github.com/foo/bar/compare/1.2.0...1.2.3",
       "https://github.com/foo/bar/compare/release-1.2.0...release-1.2.3"
     )
+    assertEquals(obtained, expected)
   }
 
   test("possibleChangelogUrls: gitlab.com") {
-    possibleReleaseRelatedUrls(
+    val obtained = possibleReleaseRelatedUrls(
       SupportedVCS.GitHub,
       uri"https://github.com",
       uri"https://gitlab.com/foo/bar",
       update
-    )
-      .map(_.url.renderString) shouldBe
+    ).map(_.url.renderString)
+    val expected =
       possibleReleaseNotesFilenames.map(name => s"https://gitlab.com/foo/bar/blob/master/$name") ++
-      possibleChangelogFilenames.map(name => s"https://gitlab.com/foo/bar/blob/master/$name") ++
-      List(
-        "https://gitlab.com/foo/bar/compare/v1.2.0...v1.2.3",
-        "https://gitlab.com/foo/bar/compare/1.2.0...1.2.3",
-        "https://gitlab.com/foo/bar/compare/release-1.2.0...release-1.2.3"
-      )
+        possibleChangelogFilenames.map(name => s"https://gitlab.com/foo/bar/blob/master/$name") ++
+        List(
+          "https://gitlab.com/foo/bar/compare/v1.2.0...v1.2.3",
+          "https://gitlab.com/foo/bar/compare/1.2.0...1.2.3",
+          "https://gitlab.com/foo/bar/compare/release-1.2.0...release-1.2.3"
+        )
+    assertEquals(obtained, expected)
   }
 
   test("possibleChangelogUrls: on-prem gitlab") {
-    possibleReleaseRelatedUrls(
+    val obtained = possibleReleaseRelatedUrls(
       SupportedVCS.GitLab,
       uri"https://gitlab.on-prem.net",
       uri"https://gitlab.on-prem.net/foo/bar",
       update
+    ).map(_.url.renderString)
+    val expected = possibleReleaseNotesFilenames.map(name =>
+      s"https://gitlab.on-prem.net/foo/bar/blob/master/$name"
+    ) ++ possibleChangelogFilenames.map(name =>
+      s"https://gitlab.on-prem.net/foo/bar/blob/master/$name"
+    ) ++ List(
+      "https://gitlab.on-prem.net/foo/bar/compare/v1.2.0...v1.2.3",
+      "https://gitlab.on-prem.net/foo/bar/compare/1.2.0...1.2.3",
+      "https://gitlab.on-prem.net/foo/bar/compare/release-1.2.0...release-1.2.3"
     )
-      .map(_.url.renderString) shouldBe
-      possibleReleaseNotesFilenames.map(name =>
-        s"https://gitlab.on-prem.net/foo/bar/blob/master/$name"
-      ) ++
-      possibleChangelogFilenames.map(name =>
-        s"https://gitlab.on-prem.net/foo/bar/blob/master/$name"
-      ) ++
-      List(
-        "https://gitlab.on-prem.net/foo/bar/compare/v1.2.0...v1.2.3",
-        "https://gitlab.on-prem.net/foo/bar/compare/1.2.0...1.2.3",
-        "https://gitlab.on-prem.net/foo/bar/compare/release-1.2.0...release-1.2.3"
-      )
+    assertEquals(obtained, expected)
   }
 
   test("possibleChangelogUrls: bitbucket.org") {
-    possibleReleaseRelatedUrls(
+    val obtained = possibleReleaseRelatedUrls(
       SupportedVCS.GitHub,
       uri"https://github.com",
       uri"https://bitbucket.org/foo/bar",
       update
-    )
-      .map(_.url.renderString) shouldBe
+    ).map(_.url.renderString)
+    val expected =
       possibleReleaseNotesFilenames.map(name => s"https://bitbucket.org/foo/bar/master/$name") ++
-      possibleChangelogFilenames.map(name => s"https://bitbucket.org/foo/bar/master/$name") ++
-      List(
-        "https://bitbucket.org/foo/bar/compare/v1.2.3..v1.2.0#diff",
-        "https://bitbucket.org/foo/bar/compare/1.2.3..1.2.0#diff",
-        "https://bitbucket.org/foo/bar/compare/release-1.2.3..release-1.2.0#diff"
-      )
+        possibleChangelogFilenames.map(name => s"https://bitbucket.org/foo/bar/master/$name") ++
+        List(
+          "https://bitbucket.org/foo/bar/compare/v1.2.3..v1.2.0#diff",
+          "https://bitbucket.org/foo/bar/compare/1.2.3..1.2.0#diff",
+          "https://bitbucket.org/foo/bar/compare/release-1.2.3..release-1.2.0#diff"
+        )
+    assertEquals(obtained, expected)
   }
 
   test("possibleChangelogUrls: homepage") {
-    possibleReleaseRelatedUrls(
+    val obtained = possibleReleaseRelatedUrls(
       SupportedVCS.GitHub,
       uri"https://github.com",
       uri"https://scalacenter.github.io/scalafix/",
       update
-    )
-      .map(_.url.renderString) shouldBe List.empty
+    ).map(_.url.renderString)
+    assertEquals(obtained, List.empty)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSRepoAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSRepoAlgTest.scala
index ae39f2a4..5479df10 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSRepoAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSRepoAlgTest.scala
@@ -1,14 +1,13 @@
 package org.scalasteward.core.vcs
 
+import munit.FunSuite
 import org.http4s.syntax.literals._
 import org.scalasteward.core.git.Branch
 import org.scalasteward.core.mock.MockContext.{config, gitAlg, vcsRepoAlg}
 import org.scalasteward.core.mock.{MockContext, MockState}
 import org.scalasteward.core.vcs.data.{Repo, RepoOut, UserOut}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class VCSRepoAlgTest extends AnyFunSuite with Matchers {
+class VCSRepoAlgTest extends FunSuite {
   val repo: Repo = Repo("fthomas", "datapackage")
   val repoDir: String = (config.workspace / "fthomas/datapackage").toString
   val envVars = List(s"GIT_ASKPASS=${config.gitAskPass}", "VAR1=val1", "VAR2=val2")
@@ -32,7 +31,7 @@ class VCSRepoAlgTest extends AnyFunSuite with Matchers {
   test("clone") {
     val state = vcsRepoAlg.clone(repo, forkRepoOut).runS(MockState.empty).unsafeRunSync()
     val url = s"https://${config.vcsLogin}@github.com/scala-steward/datapackage"
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         envVars ++ List(config.workspace.toString, "git", "clone", url, repoDir),
         envVars ++ List(repoDir, "git", "submodule", "update", "--init", "--recursive"),
@@ -40,20 +39,23 @@ class VCSRepoAlgTest extends AnyFunSuite with Matchers {
         envVars ++ List(repoDir, "git", "config", "user.name", "Bot Doe")
       )
     )
+    assertEquals(state, expected)
   }
 
   test("syncFork should throw an exception when doNotFork = false and there is no parent") {
-    vcsRepoAlg
-      .syncFork(repo, parentRepoOut)
-      .runS(MockState.empty)
-      .attempt
-      .map(_.isLeft)
-      .unsafeRunSync() shouldBe true
+    assert(
+      vcsRepoAlg
+        .syncFork(repo, parentRepoOut)
+        .runS(MockState.empty)
+        .attempt
+        .map(_.isLeft)
+        .unsafeRunSync()
+    )
   }
 
   test("syncFork should sync when doNotFork = false and there is a parent") {
     val state = vcsRepoAlg.syncFork(repo, forkRepoOut).runS(MockState.empty).unsafeRunSync()
-    state shouldBe MockState.empty.copy(
+    val expected = MockState.empty.copy(
       commands = Vector(
         envVars ++ List(
           repoDir,
@@ -69,6 +71,7 @@ class VCSRepoAlgTest extends AnyFunSuite with Matchers {
         envVars ++ List(repoDir, "git", "push", "--force", "--set-upstream", "origin", "master")
       )
     )
+    assertEquals(state, expected)
   }
 
   test("syncFork should do nothing when doNotFork = true") {
@@ -79,6 +82,6 @@ class VCSRepoAlgTest extends AnyFunSuite with Matchers {
       .runS(MockState.empty)
       .unsafeRunSync()
 
-    state shouldBe MockState.empty
+    assertEquals(state, MockState.empty)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlgTest.scala
index 3e0a9ccc..99a85df5 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlgTest.scala
@@ -2,6 +2,7 @@ package org.scalasteward.core.vcs.bitbucket
 
 import cats.effect.IO
 import io.circe.literal._
+import munit.FunSuite
 import org.http4s._
 import org.http4s.circe._
 import org.http4s.client.Client
@@ -12,10 +13,8 @@ import org.scalasteward.core.git._
 import org.scalasteward.core.mock.MockContext.config
 import org.scalasteward.core.util.HttpJsonClient
 import org.scalasteward.core.vcs.data._
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class BitbucketApiAlgTest extends AnyFunSuite with Matchers {
+class BitbucketApiAlgTest extends FunSuite {
   private val routes: HttpRoutes[IO] = HttpRoutes.of[IO] {
     case GET -> Root / "repositories" / "fthomas" / "base.g8" =>
       Ok(
@@ -142,17 +141,17 @@ class BitbucketApiAlgTest extends AnyFunSuite with Matchers {
 
   implicit val client: Client[IO] = Client.fromHttpApp(routes.orNotFound)
   implicit val httpJsonClient: HttpJsonClient[IO] = new HttpJsonClient[IO]
-  val bitbucketApiAlg = new BitbucketApiAlg[IO](
+  private val bitbucketApiAlg = new BitbucketApiAlg[IO](
     config.vcsApiHost,
     AuthenticatedUser("scala-steward", ""),
     _ => IO.pure,
     false
   )
 
-  val prUrl = uri"https://api.bitbucket.org/2.0/repositories/fthomas/base.g8/pullrequests/2"
-  val repo = Repo("fthomas", "base.g8")
-  val master = Branch("master")
-  val parent = RepoOut(
+  private val prUrl = uri"https://api.bitbucket.org/2.0/repositories/fthomas/base.g8/pullrequests/2"
+  private val repo = Repo("fthomas", "base.g8")
+  private val master = Branch("master")
+  private val parent = RepoOut(
     "base.g8",
     UserOut("fthomas"),
     None,
@@ -160,7 +159,7 @@ class BitbucketApiAlgTest extends AnyFunSuite with Matchers {
     master
   )
 
-  val fork = RepoOut(
+  private val fork = RepoOut(
     "base.g8",
     UserOut("scala-steward"),
     Some(parent),
@@ -168,36 +167,36 @@ class BitbucketApiAlgTest extends AnyFunSuite with Matchers {
     master
   )
 
-  val defaultBranch = BranchOut(
+  private val defaultBranch = BranchOut(
     master,
-    CommitOut(Sha1(HexString("07eb2a203e297c8340273950e98b2cab68b560c1")))
+    CommitOut(Sha1(HexString.unsafeFrom("07eb2a203e297c8340273950e98b2cab68b560c1")))
   )
 
-  val pullRequest =
+  private val pullRequest =
     PullRequestOut(prUrl, PullRequestState.Open, PullRequestNumber(2), "scala-steward-pr")
 
   test("createForkOrGetRepo") {
     val repoOut = bitbucketApiAlg.createForkOrGetRepo(repo, doNotFork = false).unsafeRunSync()
-    repoOut shouldBe fork
+    assertEquals(repoOut, fork)
   }
 
   test("createForkOrGetRepo without forking") {
     val repoOut = bitbucketApiAlg.createForkOrGetRepo(repo, doNotFork = true).unsafeRunSync()
-    repoOut shouldBe parent
+    assertEquals(repoOut, parent)
   }
 
   test("createForkOrGetRepoWithDefaultBranch") {
     val (repoOut, branchOut) =
       bitbucketApiAlg.createForkOrGetRepoWithDefaultBranch(repo, doNotFork = false).unsafeRunSync()
-    repoOut shouldBe fork
-    branchOut shouldBe defaultBranch
+    assertEquals(repoOut, fork)
+    assertEquals(branchOut, defaultBranch)
   }
 
   test("createForkOrGetRepoWithDefaultBranch without forking") {
     val (repoOut, branchOut) =
       bitbucketApiAlg.createForkOrGetRepoWithDefaultBranch(repo, doNotFork = true).unsafeRunSync()
-    repoOut shouldBe parent
-    branchOut shouldBe defaultBranch
+    assertEquals(repoOut, parent)
+    assertEquals(branchOut, defaultBranch)
   }
 
   test("createPullRequest") {
@@ -208,16 +207,16 @@ class BitbucketApiAlgTest extends AnyFunSuite with Matchers {
       master
     )
     val pr = bitbucketApiAlg.createPullRequest(repo, data).unsafeRunSync()
-    pr shouldBe pullRequest
+    assertEquals(pr, pullRequest)
   }
 
   test("listPullRequests") {
     val prs = bitbucketApiAlg.listPullRequests(repo, "master", master).unsafeRunSync()
-    (prs should contain).only(pullRequest)
+    assertEquals(prs, List(pullRequest))
   }
 
   test("closePullRequest") {
     val pr = bitbucketApiAlg.closePullRequest(repo, PullRequestNumber(1)).unsafeRunSync()
-    pr shouldBe pr.copy(state = PullRequestState.Closed)
+    assertEquals(pr, pr.copy(state = PullRequestState.Closed))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/JsonCodecTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/JsonCodecTest.scala
index bb38cc49..1196ff11 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/JsonCodecTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/JsonCodecTest.scala
@@ -1,11 +1,10 @@
 package org.scalasteward.core.vcs.bitbucket
 
 import io.circe.Json
+import munit.FunSuite
 import org.scalasteward.core.vcs.data.PullRequestState
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class JsonCodecTest extends AnyFunSuite with Matchers {
+class JsonCodecTest extends FunSuite {
   test("PullRequestStatus decoding of expected values") {
     val mapping = Map(
       "OPEN" -> PullRequestState.Open,
@@ -15,7 +14,7 @@ class JsonCodecTest extends AnyFunSuite with Matchers {
     )
 
     mapping.foreach { case (string, state) =>
-      json.pullRequestStateDecoder.decodeJson(Json.fromString(string)) shouldBe Right(state)
+      assertEquals(json.pullRequestStateDecoder.decodeJson(Json.fromString(string)), Right(state))
     }
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucketserver/BitbucketServerApiAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucketserver/BitbucketServerApiAlgTest.scala
index 19e48f00..0bd29781 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucketserver/BitbucketServerApiAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucketserver/BitbucketServerApiAlgTest.scala
@@ -1,6 +1,7 @@
 package org.scalasteward.core.vcs.bitbucketserver
 
 import cats.effect.IO
+import munit.FunSuite
 import org.http4s.client.Client
 import org.http4s.dsl.io._
 import org.http4s.implicits._
@@ -9,10 +10,8 @@ import org.scalasteward.core.git.Branch
 import org.scalasteward.core.mock.MockContext.config
 import org.scalasteward.core.util.HttpJsonClient
 import org.scalasteward.core.vcs.data._
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class BitbucketServerApiAlgTest extends AnyFunSuite with Matchers {
+class BitbucketServerApiAlgTest extends FunSuite {
   private val repo = Repo("scala-steward-org", "scala-steward")
   private val routes: HttpRoutes[IO] = HttpRoutes.of[IO] {
     case GET -> Root / "rest" / "api" / "1.0" / "projects" / repo.owner / "repos" / repo.repo / "pull-requests" =>
@@ -36,7 +35,7 @@ class BitbucketServerApiAlgTest extends AnyFunSuite with Matchers {
       .listPullRequests(repo, "update/sbt-1.4.2", Branch("main"))
       .unsafeRunSync()
 
-    pullRequests shouldBe List(
+    val expected = List(
       PullRequestOut(
         Uri.unsafeFromString("http://example.org"),
         PullRequestState.Open,
@@ -44,5 +43,7 @@ class BitbucketServerApiAlgTest extends AnyFunSuite with Matchers {
         "Update sbt to 1.4.2"
       )
     )
+
+    assertEquals(pullRequests, expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/BranchOutTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/BranchOutTest.scala
index a5d97c2e..264b3555 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/BranchOutTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/BranchOutTest.scala
@@ -1,21 +1,20 @@
 package org.scalasteward.core.vcs.data
 
 import io.circe.parser
+import munit.FunSuite
 import org.scalasteward.core.git.Sha1.HexString
 import org.scalasteward.core.git.{Branch, Sha1}
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 import scala.io.Source
 
-class BranchOutTest extends AnyFunSuite with Matchers {
+class BranchOutTest extends FunSuite {
   test("decode") {
     val input = Source.fromResource("get-branch.json").mkString
-    parser.decode[BranchOut](input) shouldBe
-      Right(
-        BranchOut(
-          Branch("master"),
-          CommitOut(Sha1(HexString("7fd1a60b01f91b314f59955a4e4d4e80d8edf11d")))
-        )
+    val expected = Right(
+      BranchOut(
+        Branch("master"),
+        CommitOut(Sha1(HexString.unsafeFrom("7fd1a60b01f91b314f59955a4e4d4e80d8edf11d")))
       )
+    )
+    assertEquals(parser.decode[BranchOut](input), expected)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/NewPullRequestDataTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/NewPullRequestDataTest.scala
index 2917ba36..37feff8d 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/NewPullRequestDataTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/NewPullRequestDataTest.scala
@@ -1,6 +1,7 @@
 package org.scalasteward.core.vcs.data
 
 import io.circe.syntax._
+import munit.FunSuite
 import org.http4s.syntax.literals._
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.buildtool.sbt.data.SbtVersion
@@ -10,10 +11,8 @@ import org.scalasteward.core.nurture.UpdateData
 import org.scalasteward.core.repoconfig.RepoConfig
 import org.scalasteward.core.scalafix.Migration
 import org.scalasteward.core.util.Nel
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class NewPullRequestDataTest extends AnyFunSuite with Matchers {
+class NewPullRequestDataTest extends FunSuite {
   test("asJson") {
     val data = UpdateData(
       Repo("foo", "bar"),
@@ -21,75 +20,88 @@ class NewPullRequestDataTest extends AnyFunSuite with Matchers {
       RepoConfig(),
       Update.Single("ch.qos.logback" % "logback-classic" % "1.2.0", Nel.of("1.2.3")),
       Branch("master"),
-      Sha1(Sha1.HexString("d6b6791d2ea11df1d156fe70979ab8c3a5ba3433")),
+      Sha1(Sha1.HexString.unsafeFrom("d6b6791d2ea11df1d156fe70979ab8c3a5ba3433")),
       Branch("update/logback-classic-1.2.3")
     )
-    NewPullRequestData
+    val obtained = NewPullRequestData
       .from(data, "scala-steward:update/logback-classic-1.2.3")
       .asJson
-      .spaces2 shouldBe
+      .spaces2
+    val expected =
       raw"""|{
             |  "title" : "Update logback-classic to 1.2.3",
             |  "body" : "Updates ch.qos.logback:logback-classic from 1.2.0 to 1.2.3.\n\n\nI'll automatically update this PR to resolve conflicts as long as you don't change it yourself.\n\nIf you'd like to skip this version, you can just close this PR. If you have any feedback, just mention me in the comments below.\n\nConfigure Scala Steward for your repository with a [`.scala-steward.conf`](https://github.com/scala-steward-org/scala-steward/blob/${org.scalasteward.core.BuildInfo.gitHeadCommit}/docs/repo-specific-configuration.md) file.\n\nHave a fantastic day writing Scala!\n\n<details>\n<summary>Ignore future updates</summary>\n\nAdd this to your `.scala-steward.conf` file to ignore future updates of this dependency:\n```\nupdates.ignore = [ { groupId = \"ch.qos.logback\", artifactId = \"logback-classic\" } ]\n```\n</details>\n\nlabels: library-update, semver-patch",
             |  "head" : "scala-steward:update/logback-classic-1.2.3",
             |  "base" : "master"
             |}""".stripMargin
+    assertEquals(obtained, expected)
   }
 
   test("fromTo") {
-    NewPullRequestData.fromTo(
-      Update.Single("com.example" % "foo" % "1.2.0", Nel.of("1.2.3"))
-    ) shouldBe "from 1.2.0 to 1.2.3"
+    assertEquals(
+      NewPullRequestData.fromTo(
+        Update.Single("com.example" % "foo" % "1.2.0", Nel.of("1.2.3"))
+      ),
+      "from 1.2.0 to 1.2.3"
+    )
   }
 
   test("links to release notes/changelog") {
-    NewPullRequestData.releaseNote(List.empty) shouldBe None
+    assertEquals(NewPullRequestData.releaseNote(List.empty), None)
 
-    NewPullRequestData.releaseNote(
-      List(ReleaseRelatedUrl.CustomChangelog(uri"https://github.com/foo/foo/CHANGELOG.rst"))
-    ) shouldBe Some(
-      "[Changelog](https://github.com/foo/foo/CHANGELOG.rst)"
+    assertEquals(
+      NewPullRequestData.releaseNote(
+        List(ReleaseRelatedUrl.CustomChangelog(uri"https://github.com/foo/foo/CHANGELOG.rst"))
+      ),
+      Some("[Changelog](https://github.com/foo/foo/CHANGELOG.rst)")
     )
 
-    NewPullRequestData.releaseNote(
-      List(
-        ReleaseRelatedUrl.CustomChangelog(uri"https://github.com/foo/foo/CHANGELOG.rst"),
-        ReleaseRelatedUrl.GitHubReleaseNotes(uri"https://github.com/foo/foo/releases/tag/v1.2.3"),
-        ReleaseRelatedUrl.CustomReleaseNotes(
-          uri"https://github.com/foo/bar/blob/master/ReleaseNotes.md"
-        ),
-        ReleaseRelatedUrl.CustomReleaseNotes(
-          uri"https://github.com/foo/bar/blob/master/Releases.md"
-        ),
-        ReleaseRelatedUrl.VersionDiff(uri"https://github.com/foo/foo/compare/v1.2.0...v1.2.3")
+    assertEquals(
+      NewPullRequestData.releaseNote(
+        List(
+          ReleaseRelatedUrl.CustomChangelog(uri"https://github.com/foo/foo/CHANGELOG.rst"),
+          ReleaseRelatedUrl.GitHubReleaseNotes(uri"https://github.com/foo/foo/releases/tag/v1.2.3"),
+          ReleaseRelatedUrl.CustomReleaseNotes(
+            uri"https://github.com/foo/bar/blob/master/ReleaseNotes.md"
+          ),
+          ReleaseRelatedUrl.CustomReleaseNotes(
+            uri"https://github.com/foo/bar/blob/master/Releases.md"
+          ),
+          ReleaseRelatedUrl.VersionDiff(uri"https://github.com/foo/foo/compare/v1.2.0...v1.2.3")
+        )
+      ),
+      Some(
+        "[Changelog](https://github.com/foo/foo/CHANGELOG.rst) - [GitHub Release Notes](https://github.com/foo/foo/releases/tag/v1.2.3) - [Release Notes](https://github.com/foo/bar/blob/master/ReleaseNotes.md) - [Release Notes](https://github.com/foo/bar/blob/master/Releases.md) - [Version Diff](https://github.com/foo/foo/compare/v1.2.0...v1.2.3)"
       )
-    ) shouldBe Some(
-      "[Changelog](https://github.com/foo/foo/CHANGELOG.rst) - [GitHub Release Notes](https://github.com/foo/foo/releases/tag/v1.2.3) - [Release Notes](https://github.com/foo/bar/blob/master/ReleaseNotes.md) - [Release Notes](https://github.com/foo/bar/blob/master/Releases.md) - [Version Diff](https://github.com/foo/foo/compare/v1.2.0...v1.2.3)"
     )
   }
 
   test("showing artifacts with URL in Markdown format") {
-    NewPullRequestData.artifactsWithOptionalUrl(
-      Update.Single("com.example" % "foo" % "1.2.0", Nel.of("1.2.3")),
-      Map("foo" -> uri"https://github.com/foo/foo")
-    ) shouldBe "[com.example:foo](https://github.com/foo/foo)"
-
-    NewPullRequestData.artifactsWithOptionalUrl(
-      Update.Group("com.example" % Nel.of("foo", "bar") % "1.2.0", Nel.of("1.2.3")),
-      Map("foo" -> uri"https://github.com/foo/foo", "bar" -> uri"https://github.com/bar/bar")
-    ) shouldBe
+    assertEquals(
+      NewPullRequestData.artifactsWithOptionalUrl(
+        Update.Single("com.example" % "foo" % "1.2.0", Nel.of("1.2.3")),
+        Map("foo" -> uri"https://github.com/foo/foo")
+      ),
+      "[com.example:foo](https://github.com/foo/foo)"
+    )
+    assertEquals(
+      NewPullRequestData.artifactsWithOptionalUrl(
+        Update.Group("com.example" % Nel.of("foo", "bar") % "1.2.0", Nel.of("1.2.3")),
+        Map("foo" -> uri"https://github.com/foo/foo", "bar" -> uri"https://github.com/bar/bar")
+      ),
       """
         |* [com.example:foo](https://github.com/foo/foo)
         |* [com.example:bar](https://github.com/bar/bar)
         |
         |""".stripMargin
+    )
   }
 
   test("migrationNote: when no migrations") {
     val (label, appliedMigrations) = NewPullRequestData.migrationNote(List.empty)
 
-    label shouldBe None
-    appliedMigrations shouldBe None
+    assertEquals(label, None)
+    assertEquals(appliedMigrations, None)
   }
 
   test("migrationNote: when artifact has migrations") {
@@ -104,14 +116,16 @@ class NewPullRequestDataTest extends AnyFunSuite with Matchers {
     )
     val (label, appliedMigrations) = NewPullRequestData.migrationNote(List(migration))
 
-    label shouldBe Some("scalafix-migrations")
-    appliedMigrations.fold("")(_.toHtml) shouldBe
+    assertEquals(label, Some("scalafix-migrations"))
+    assertEquals(
+      appliedMigrations.fold("")(_.toHtml),
       """<details>
         |<summary>Applied Migrations</summary>
         |
         |* I am a rewrite rule
         |</details>
       """.stripMargin.trim
+    )
   }
 
   test("migrationNote: when artifact has migrations with docs") {
@@ -126,8 +140,9 @@ class NewPullRequestDataTest extends AnyFunSuite with Matchers {
     )
     val (label, appliedMigrations) = NewPullRequestData.migrationNote(List(migration))
 
-    label shouldBe Some("scalafix-migrations")
-    appliedMigrations.fold("")(_.toHtml) shouldBe
+    assertEquals(label, Some("scalafix-migrations"))
+    assertEquals(
+      appliedMigrations.fold("")(_.toHtml),
       """<details>
         |<summary>Applied Migrations</summary>
         |
@@ -138,23 +153,31 @@ class NewPullRequestDataTest extends AnyFunSuite with Matchers {
         |* https://scalacenter.github.io/scalafix/
         |</details>
       """.stripMargin.trim
+    )
   }
 
   test("updateType") {
     val dependency = "com.example" % "foo" % "0.1"
     val single = Update.Single(dependency, Nel.of("0.2"))
     val group = Update.Group("com.example" % Nel.of("foo", "bar") % "0.1", Nel.of("0.2"))
-    NewPullRequestData.updateType(single) shouldBe "library-update"
-    NewPullRequestData.updateType(group) shouldBe "library-update"
+    assertEquals(NewPullRequestData.updateType(single), "library-update")
+    assertEquals(NewPullRequestData.updateType(group), "library-update")
 
-    NewPullRequestData.updateType(
-      Update.Single(dependency % "test", Nel.of("0.2"))
-    ) shouldBe "test-library-update"
-    NewPullRequestData.updateType(
-      Update.Single(dependency.copy(sbtVersion = Some(SbtVersion("1.0"))), Nel.of("0.2"))
-    ) shouldBe "sbt-plugin-update"
-    NewPullRequestData.updateType(
-      Update.Single(dependency.copy(configurations = Some("scalafix-rule")), Nel.of("0.2"))
-    ) shouldBe "scalafix-rule-update"
+    assertEquals(
+      NewPullRequestData.updateType(Update.Single(dependency % "test", Nel.of("0.2"))),
+      "test-library-update"
+    )
+    assertEquals(
+      NewPullRequestData.updateType(
+        Update.Single(dependency.copy(sbtVersion = Some(SbtVersion("1.0"))), Nel.of("0.2"))
+      ),
+      "sbt-plugin-update"
+    )
+    assertEquals(
+      NewPullRequestData.updateType(
+        Update.Single(dependency.copy(configurations = Some("scalafix-rule")), Nel.of("0.2"))
+      ),
+      "scalafix-rule-update"
+    )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/PullRequestOutTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/PullRequestOutTest.scala
index 31143178..5ad5a2e0 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/PullRequestOutTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/PullRequestOutTest.scala
@@ -1,13 +1,12 @@
 package org.scalasteward.core.vcs.data
 
 import io.circe.parser
+import munit.FunSuite
 import org.http4s.syntax.literals._
 import org.scalasteward.core.vcs.data.PullRequestState.Open
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 import scala.io.Source
 
-class PullRequestOutTest extends AnyFunSuite with Matchers {
+class PullRequestOutTest extends FunSuite {
   test("decode") {
     val expected =
       List(
@@ -20,6 +19,6 @@ class PullRequestOutTest extends AnyFunSuite with Matchers {
       )
 
     val input = Source.fromResource("list-pull-requests.json").mkString
-    parser.decode[List[PullRequestOut]](input) shouldBe Right(expected)
+    assertEquals(parser.decode[List[PullRequestOut]](input), Right(expected))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/PullRequestStateTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/PullRequestStateTest.scala
index 53f0851f..c1115e8b 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/PullRequestStateTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/PullRequestStateTest.scala
@@ -2,14 +2,12 @@ package org.scalasteward.core.vcs.data
 
 import io.circe.Decoder
 import io.circe.syntax._
+import munit.FunSuite
 import org.scalasteward.core.vcs.data.PullRequestState.{Closed, Open}
-import org.scalatest.Assertion
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class PullRequestStateTest extends AnyFunSuite with Matchers {
-  def roundTrip(state: PullRequestState): Assertion =
-    Decoder[PullRequestState].decodeJson(state.asJson) shouldBe Right(state)
+class PullRequestStateTest extends FunSuite {
+  def roundTrip(state: PullRequestState): Unit =
+    assertEquals(Decoder[PullRequestState].decodeJson(state.asJson), Right(state))
 
   test("round-trip") {
     roundTrip(Open)
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/RepoOutTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/RepoOutTest.scala
index 9bde1e8f..2f8ac114 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/RepoOutTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/RepoOutTest.scala
@@ -2,14 +2,13 @@ package org.scalasteward.core.vcs.data
 
 import cats.effect.IO
 import io.circe.parser
+import munit.FunSuite
 import org.http4s.syntax.literals._
 import org.scalasteward.core.git.Branch
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 import scala.io.Source
 
-class RepoOutTest extends AnyFunSuite with Matchers {
-  val parent =
+class RepoOutTest extends FunSuite {
+  private val parent =
     RepoOut(
       "base.g8",
       UserOut("ChristopherDavenport"),
@@ -18,7 +17,7 @@ class RepoOutTest extends AnyFunSuite with Matchers {
       Branch("master")
     )
 
-  val fork =
+  private val fork =
     RepoOut(
       "base.g8-1",
       UserOut("scala-steward"),
@@ -29,14 +28,14 @@ class RepoOutTest extends AnyFunSuite with Matchers {
 
   test("decode") {
     val input = Source.fromResource("create-fork.json").mkString
-    parser.decode[RepoOut](input) shouldBe Right(fork)
+    assertEquals(parser.decode[RepoOut](input), Right(fork))
   }
 
   test("parentOrRaise") {
-    fork.parentOrRaise[IO].unsafeRunSync() shouldBe parent
+    assertEquals(fork.parentOrRaise[IO].unsafeRunSync(), parent)
   }
 
   test("repo") {
-    fork.repo shouldBe Repo("scala-steward", "base.g8-1")
+    assertEquals(fork.repo, Repo("scala-steward", "base.g8-1"))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/RepoTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/RepoTest.scala
index adb39aec..f1573de7 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/RepoTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/RepoTest.scala
@@ -1,15 +1,14 @@
 package org.scalasteward.core.vcs.data
 
+import munit.FunSuite
 import org.scalasteward.core.vcs.data.Repo.repoKeyDecoder
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class RepoTest extends AnyFunSuite with Matchers {
+class RepoTest extends FunSuite {
   test("decode") {
-    repoKeyDecoder("owner/repo") shouldBe Some(Repo("owner", "repo"))
+    assertEquals(repoKeyDecoder("owner/repo"), Some(Repo("owner", "repo")))
   }
 
   test("decode sub group") {
-    repoKeyDecoder("group1/group2/project1") shouldBe Some(Repo("group1/group2", "project1"))
+    assertEquals(repoKeyDecoder("group1/group2/project1"), Some(Repo("group1/group2", "project1")))
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/github/GitHubApiAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/github/GitHubApiAlgTest.scala
index 135c2197..4725265f 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/github/GitHubApiAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/github/GitHubApiAlgTest.scala
@@ -2,6 +2,7 @@ package org.scalasteward.core.vcs.github
 
 import cats.effect.IO
 import io.circe.literal._
+import munit.FunSuite
 import org.http4s.HttpRoutes
 import org.http4s.circe._
 import org.http4s.client.Client
@@ -12,10 +13,8 @@ import org.scalasteward.core.git.{Branch, Sha1}
 import org.scalasteward.core.mock.MockContext.config
 import org.scalasteward.core.util.HttpJsonClient
 import org.scalasteward.core.vcs.data._
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class GitHubApiAlgTest extends AnyFunSuite with Matchers {
+class GitHubApiAlgTest extends FunSuite {
   val routes: HttpRoutes[IO] =
     HttpRoutes.of[IO] {
       case GET -> Root / "repos" / "fthomas" / "base.g8" =>
@@ -81,9 +80,9 @@ class GitHubApiAlgTest extends AnyFunSuite with Matchers {
   implicit val httpJsonClient: HttpJsonClient[IO] = new HttpJsonClient[IO]
   val gitHubApiAlg = new GitHubApiAlg[IO](config.vcsApiHost, _ => IO.pure)
 
-  val repo = Repo("fthomas", "base.g8")
+  private val repo = Repo("fthomas", "base.g8")
 
-  val parent = RepoOut(
+  private val parent = RepoOut(
     "base.g8",
     UserOut("fthomas"),
     None,
@@ -91,7 +90,7 @@ class GitHubApiAlgTest extends AnyFunSuite with Matchers {
     Branch("master")
   )
 
-  val fork = RepoOut(
+  private val fork = RepoOut(
     "base.g8-1",
     UserOut("scala-steward"),
     Some(parent),
@@ -99,37 +98,37 @@ class GitHubApiAlgTest extends AnyFunSuite with Matchers {
     Branch("master")
   )
 
-  val defaultBranch = BranchOut(
+  private val defaultBranch = BranchOut(
     Branch("master"),
     CommitOut(Sha1(HexString("07eb2a203e297c8340273950e98b2cab68b560c1")))
   )
 
   test("createForkOrGetRepo") {
     val repoOut = gitHubApiAlg.createForkOrGetRepo(repo, doNotFork = false).unsafeRunSync()
-    repoOut shouldBe fork
+    assertEquals(repoOut, fork)
   }
 
   test("createForkOrGetRepo without forking") {
     val repoOut = gitHubApiAlg.createForkOrGetRepo(repo, doNotFork = true).unsafeRunSync()
-    repoOut shouldBe parent
+    assertEquals(repoOut, parent)
   }
 
   test("createForkOrGetRepoWithDefaultBranch") {
     val (repoOut, branchOut) =
       gitHubApiAlg.createForkOrGetRepoWithDefaultBranch(repo, doNotFork = false).unsafeRunSync()
-    repoOut shouldBe fork
-    branchOut shouldBe defaultBranch
+    assertEquals(repoOut, fork)
+    assertEquals(branchOut, defaultBranch)
   }
 
   test("createForkOrGetRepoWithDefaultBranch without forking") {
     val (repoOut, branchOut) =
       gitHubApiAlg.createForkOrGetRepoWithDefaultBranch(repo, doNotFork = true).unsafeRunSync()
-    repoOut shouldBe parent
-    branchOut shouldBe defaultBranch
+    assertEquals(repoOut, parent)
+    assertEquals(branchOut, defaultBranch)
   }
 
   test("closePullRequest") {
     val prOut = gitHubApiAlg.closePullRequest(repo, PullRequestNumber(1347)).unsafeRunSync()
-    prOut.state shouldBe PullRequestState.Closed
+    assertEquals(prOut.state, PullRequestState.Closed)
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/github/UrlTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/github/UrlTest.scala
index e71b0a6f..797be1fb 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/github/UrlTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/github/UrlTest.scala
@@ -1,44 +1,44 @@
 package org.scalasteward.core.vcs.github
 
+import munit.FunSuite
 import org.http4s.syntax.literals._
 import org.scalasteward.core.git.Branch
 import org.scalasteward.core.vcs.data.Repo
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class UrlTest extends AnyFunSuite with Matchers {
-  val url = new Url(uri"https://api.github.com")
+class UrlTest extends FunSuite {
+  private val url = new Url(uri"https://api.github.com")
   import url._
 
-  val repo = Repo("fthomas", "refined")
-  val branch = Branch("master")
+  private val repo = Repo("fthomas", "refined")
+  private val branch = Branch("master")
 
   test("branches") {
-    branches(repo, branch).toString shouldBe
+    assertEquals(
+      branches(repo, branch).toString,
       "https://api.github.com/repos/fthomas/refined/branches/master"
+    )
   }
 
   test("forks") {
-    forks(repo).toString shouldBe
-      "https://api.github.com/repos/fthomas/refined/forks"
+    assertEquals(forks(repo).toString, "https://api.github.com/repos/fthomas/refined/forks")
   }
 
   test("listPullRequests") {
-    listPullRequests(
-      repo,
-      "scala-steward:update/fs2-core-1.0.0",
-      Branch("series/0.6.x")
-    ).toString shouldBe
+    assertEquals(
+      listPullRequests(
+        repo,
+        "scala-steward:update/fs2-core-1.0.0",
+        Branch("series/0.6.x")
+      ).toString,
       "https://api.github.com/repos/fthomas/refined/pulls?head=scala-steward%3Aupdate/fs2-core-1.0.0&base=series/0.6.x&state=all"
+    )
   }
 
   test("pulls") {
-    pulls(repo).toString shouldBe
-      "https://api.github.com/repos/fthomas/refined/pulls"
+    assertEquals(pulls(repo).toString, "https://api.github.com/repos/fthomas/refined/pulls")
   }
 
   test("repos") {
-    repos(repo).toString shouldBe
-      "https://api.github.com/repos/fthomas/refined"
+    assertEquals(repos(repo).toString, "https://api.github.com/repos/fthomas/refined")
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/github/authenticationTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/github/authenticationTest.scala
index 62beaa32..ccee0734 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/github/authenticationTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/github/authenticationTest.scala
@@ -1,19 +1,20 @@
 package org.scalasteward.core.vcs.github
 
 import cats.Id
+import munit.FunSuite
 import org.http4s.headers.{Accept, Authorization}
 import org.http4s.{BasicCredentials, Headers, MediaType, Request}
 import org.scalasteward.core.vcs.data.AuthenticatedUser
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
 
-class authenticationTest extends AnyFunSuite with Matchers {
+class authenticationTest extends FunSuite {
   test("addCredentials") {
     val request = authentication
       .addCredentials[Id](AuthenticatedUser("user", "pass"))
       .apply(Request(headers = Headers.of(Accept(MediaType.text.plain))))
 
-    request.headers shouldBe
+    assertEquals(
+      request.headers,
       Headers.of(Accept(MediaType.text.plain), Authorization(BasicCredentials("user", "pass")))
+    )
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/gitlab/GitLabApiAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/gitlab/GitLabApiAlgTest.scala
index f9c372c1..571fae09 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/gitlab/GitLabApiAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/gitlab/GitLabApiAlgTest.scala
@@ -2,9 +2,11 @@ package org.scalasteward.core.vcs.gitlab
 
 import cats.effect.IO
 import cats.implicits._
+import io.chrisdavenport.log4cats.Logger
 import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
 import io.circe.literal._
 import io.circe.parser._
+import munit.FunSuite
 import org.http4s.HttpRoutes
 import org.http4s.circe._
 import org.http4s.client.Client
@@ -19,12 +21,9 @@ import org.scalasteward.core.nurture.UpdateData
 import org.scalasteward.core.repoconfig.RepoConfig
 import org.scalasteward.core.util.{HttpJsonClient, Nel}
 import org.scalasteward.core.vcs.data._
-import org.scalatest.funsuite.AnyFunSuite
-import org.scalatest.matchers.should.Matchers
-
-class GitLabApiAlgTest extends AnyFunSuite with Matchers {
-  import org.scalasteward.core.vcs.gitlab.GitLabJsonCodec._
+import org.scalasteward.core.vcs.gitlab.GitLabJsonCodec._
 
+class GitLabApiAlgTest extends FunSuite {
   object MergeWhenPipelineSucceedsMatcher
       extends QueryParamDecoderMatcher[Boolean]("merge_when_pipeline_succeeds")
 
@@ -72,7 +71,7 @@ class GitLabApiAlgTest extends AnyFunSuite with Matchers {
 
   implicit val client: Client[IO] = Client.fromHttpApp(routes.orNotFound)
   implicit val httpJsonClient: HttpJsonClient[IO] = new HttpJsonClient[IO]
-  implicit val logger = Slf4jLogger.getLogger[IO]
+  implicit val logger: Logger[IO] = Slf4jLogger.getLogger[IO]
   val gitlabApiAlg =
     new GitLabApiAlg[IO](
       config.vcsApiHost,
@@ -82,30 +81,29 @@ class GitLabApiAlgTest extends AnyFunSuite with Matchers {
       mergeWhenPipelineSucceeds = false
     )
 
-  val data = UpdateData(
+  private val data = UpdateData(
     Repo("foo", "bar"),
     Repo("scala-steward", "bar"),
     RepoConfig(),
     Update.Single("ch.qos.logback" % "logback-classic" % "1.2.0", Nel.of("1.2.3")),
     Branch("master"),
-    Sha1(Sha1.HexString("d6b6791d2ea11df1d156fe70979ab8c3a5ba3433")),
+    Sha1(Sha1.HexString.unsafeFrom("d6b6791d2ea11df1d156fe70979ab8c3a5ba3433")),
     Branch("update/logback-classic-1.2.3")
   )
-  val newPRData =
+  private val newPRData =
     NewPullRequestData.from(data, "scala-steward:update/logback-classic-1.2.3")
 
   test("createPullRequest") {
-    val prOut =
-      gitlabApiAlg
-        .createPullRequest(Repo("foo", "bar"), newPRData)
-        .unsafeRunSync()
-
-    prOut shouldBe PullRequestOut(
+    val prOut = gitlabApiAlg
+      .createPullRequest(Repo("foo", "bar"), newPRData)
+      .unsafeRunSync()
+    val expected = PullRequestOut(
       uri"https://gitlab.com/foo/bar/merge_requests/7115",
       PullRequestState.Open,
       PullRequestNumber(7115),
       "title"
     )
+    assertEquals(prOut, expected)
   }
 
   test("createPullRequest -- no fork") {
@@ -121,31 +119,30 @@ class GitLabApiAlgTest extends AnyFunSuite with Matchers {
       gitlabApiAlgNoFork
         .createPullRequest(Repo("foo", "bar"), newPRData)
         .unsafeRunSync()
-
-    prOut shouldBe PullRequestOut(
+    val expected = PullRequestOut(
       uri"https://gitlab.com/foo/bar/merge_requests/150",
       PullRequestState.Open,
       PullRequestNumber(150),
       "title"
     )
+    assertEquals(prOut, expected)
   }
 
   test("extractProjectId") {
-    decode[ProjectId](getRepo.spaces2) shouldBe Right(ProjectId(12414871L))
+    assertEquals(decode[ProjectId](getRepo.spaces2), Right(ProjectId(12414871L)))
   }
 
   test("closePullRequest") {
-    val prOut =
-      gitlabApiAlg
-        .closePullRequest(Repo("foo", "bar"), PullRequestNumber(7115))
-        .unsafeRunSync()
-
-    prOut shouldBe PullRequestOut(
+    val prOut = gitlabApiAlg
+      .closePullRequest(Repo("foo", "bar"), PullRequestNumber(7115))
+      .unsafeRunSync()
+    val expected = PullRequestOut(
       uri"https://gitlab.com/foo/bar/merge_requests/7115",
       PullRequestState.Closed,
       PullRequestNumber(7115),
       "title"
     )
+    assertEquals(prOut, expected)
   }
 
   test("createPullRequest -- auto merge") {
@@ -158,17 +155,18 @@ class GitLabApiAlgTest extends AnyFunSuite with Matchers {
         mergeWhenPipelineSucceeds = true
       )
 
-    val prOut =
-      gitlabApiAlgNoFork
-        .createPullRequest(Repo("foo", "bar"), newPRData)
-        .unsafeRunSync()
+    val prOut = gitlabApiAlgNoFork
+      .createPullRequest(Repo("foo", "bar"), newPRData)
+      .unsafeRunSync()
 
-    prOut shouldBe PullRequestOut(
+    val expected = PullRequestOut(
       uri"https://gitlab.com/foo/bar/merge_requests/150",
       PullRequestState.Open,
       PullRequestNumber(150),
       "title"
     )
+
+    assertEquals(prOut, expected)
   }
 
   test("createPullRequest -- don't fail on error code") {
@@ -197,12 +195,14 @@ class GitLabApiAlgTest extends AnyFunSuite with Matchers {
         .createPullRequest(Repo("foo", "bar"), newPRData)
         .unsafeRunSync()
 
-    prOut shouldBe PullRequestOut(
+    val expected = PullRequestOut(
       uri"https://gitlab.com/foo/bar/merge_requests/150",
       PullRequestState.Open,
       PullRequestNumber(150),
       "title"
     )
+
+    assertEquals(prOut, expected)
   }
 
   val getMr = json"""