模拟与测试装置
测试设置
模拟与测试装置 是 CoddyKit 上的免费 Scala for Backend Engineering & Functional Programming 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Scala for Backend Engineering & Functional Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
测试设置与清理
许多测试需要共享的测试夹具:在测试前准备好的数据或资源,以及测试后需要清理的内容。ScalaTest 提供了多种管理方式,无需重复编写设置代码。
简单夹具:只需一个方法
最简单的夹具是一个用于构建全新状态的辅助方法。每个测试都调用它,从而保证隔离。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class StackSpec extends AnyFlatSpec with Matchers {
def emptyStack(): scala.collection.mutable.Stack[Int] =
scala.collection.mutable.Stack.empty[Int]
"a stack" should "start empty" in {
emptyStack().size shouldBe 0
}
}BeforeAndAfter
混入 BeforeAndAfter,即可使用 before { } 和 after { } 代码块,在每个测试前后运行代码。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalatest.BeforeAndAfter
class DbSpec extends AnyFlatSpec with Matchers with BeforeAndAfter {
var counter = 0
before { counter = 10 }
after { counter = 0 }
"counter" should "be initialized" in {
counter shouldBe 10
}
}BeforeAndAfterAll
对于测试套件中所有测试共享的昂贵资源(例如数据库连接或嵌入式服务器),请将 BeforeAndAfterAll 与 beforeAll 和 afterAll 一起使用。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.BeforeAndAfterAll
class ServerSpec extends AnyFlatSpec with BeforeAndAfterAll {
override def beforeAll(): Unit = println("start server")
override def afterAll(): Unit = println("stop server")
"server" should "respond" in {
assert(true)
}
}借用夹具模式
借用模式将新构建的资源传递给测试主体,并在 finally 中保证清理,即使测试失败也不例外。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class FileSpec extends AnyFlatSpec with Matchers {
def withBuffer(test: StringBuilder => Any): Unit = {
val buf = new StringBuilder("init")
try test(buf)
finally buf.clear()
}
"a buffer" should "start with init" in withBuffer { buf =>
buf.toString shouldBe "init"
}
}为什么要使用模拟
模拟对象是真实依赖项(例如数据库或 HTTP 客户端)的替代品,可以让单元测试保持快速且具有确定性。您可以控制模拟对象返回的内容,并验证它被如何调用。
添加 Mockito
ScalaTest 通过 scalatestplus 与 Mockito 集成。添加依赖后,混入 MockitoSugar。
libraryDependencies += "org.scalatestplus" %% "mockito-5-10" % "3.2.18.0" % Test模拟方法
创建模拟对象,并使用 when(...).thenReturn(...) 为其行为编程。然后,测试会执行依赖该模拟对象的代码。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.mockito.MockitoSugar
import org.mockito.Mockito.when
trait Repo { def find(id: Int): String }
class RepoSpec extends AnyFlatSpec with Matchers with MockitoSugar {
"a repo" should "return stubbed value" in {
val repo = mock[Repo]
when(repo.find(1)).thenReturn("Alice")
repo.find(1) shouldBe "Alice"
}
}验证交互
除了返回值之外,您还可以使用 verify 验证某个方法是否按预期次数被调用。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatestplus.mockito.MockitoSugar
import org.mockito.Mockito.{verify, times}
trait Logger { def log(msg: String): Unit }
class LogSpec extends AnyFlatSpec with MockitoSugar {
"a service" should "log once" in {
val logger = mock[Logger]
logger.log("hi")
verify(logger, times(1)).log("hi")
}
}模拟对象、存根与伪实现
术语:
- 存根:返回预先设定的答案。
- 模拟对象:还允许您验证交互。
- 伪实现:轻量级的可运行实现(例如内存中的仓库)。
简单情况下优先使用伪实现或真实对象;只有真正的外部依赖才使用模拟对象。
保持测试隔离
夹具和模拟对象的目标相同:让每个测试都在已知且独立的状态下运行。在每个测试前重置共享的可变状态,并避免在测试之间共享可变夹具,以防止出现不稳定且依赖执行顺序的失败。
快速检查
检查您对夹具和模拟的了解。
回顾
您学习了夹具和模拟:
- 夹具:辅助方法、
BeforeAndAfter、BeforeAndAfterAll以及借用模式。 - 模拟对象(通过 MockitoSugar):使用
when().thenReturn()创建存根,使用verify检查调用。 - 简单情况下优先使用伪实现;对外部依赖使用模拟对象。
- 确保每个测试相互隔离且不依赖执行顺序。
常见问题解答
「模拟与测试装置」课时是免费的吗?
是的 — 「模拟与测试装置」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Scala for Backend Engineering & Functional Programming 课程的其余内容,请升级到 CoddyKit PRO。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
「模拟与测试装置」这节课中我会学到什么?
测试设置 你通过在浏览器中直接运行的动手代码来练习 Scala for Backend Engineering & Functional Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Scala for Backend Engineering & Functional Programming 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Scala for Backend Engineering & Functional Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「模拟与测试装置」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Scala for Backend Engineering & Functional Programming 课中编写并运行代码吗?
能。每节 Scala for Backend Engineering & Functional Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- ScalaTest 风格
- 匹配器
- 基于属性的测试
- 模拟与测试装置