如何使用ScalaTest和Akka HTTP测试路由中的连接失败场景?
没问题,我来一步步拆解怎么用ScalaTest + Akka HTTP测试你这个路由的数据库连接失败场景。核心思路是模拟数据库操作抛出异常,然后验证路由的错误处理逻辑是否符合预期。
首先,你需要先完善路由里的异常处理分支——你原来的代码里case F...没写完,得补上数据库连接失败时的处理,比如:
case Failure(_) => complete(StatusCodes.InternalServerError -> "connectionFail")
接下来,我们用ScalaTest + Akka HTTP TestKit + Mockito(用来模拟数据库层)来写测试:
1. 准备测试基础类
先搭建测试的骨架,引入必要的依赖并初始化测试路由和模拟的数据库实例:
import org.scalatest.BeforeAndAfterEach import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import akka.http.scaladsl.testkit.ScalatestRouteTest import akka.http.scaladsl.model._ import java.util.UUID import org.mockito.Mockito._ import org.mockito.ArgumentMatchers._ import scala.concurrent.Future // 假设你的路由依赖的Database定义和RuleRow实体是这样的(根据你的实际代码调整) trait Database { def findById(id: UUID): Future[Option[RuleRow]] def update(row: RuleRow): Future[Int] } case class RuleRow(id: UUID, test: Boolean) class RulesRouteSpec extends AnyWordSpec with Matchers with ScalatestRouteTest with BeforeAndAfterEach { // 模拟数据库实例 private val mockDatabase = mock[Database] // 初始化测试用的路由(假设你的路由类通过构造注入接收Database) private val testRoute = new YourRulesRouteClass(mockDatabase).route // 每次测试前重置mock,避免测试间状态污染 override def beforeEach(): Unit = { reset(mockDatabase) }
2. 测试「查找数据时数据库连接失败」场景
这个场景对应findById抛出异常的情况,我们要验证路由返回500错误和对应提示:
"PUT /rules/{id}" should { "return 500 Internal Server Error when database connection fails during lookup" in { val testId = UUID.randomUUID() // 模拟findById方法抛出连接失败的异常 when(mockDatabase.findById(eqTo(testId))) .thenReturn(Future.failed(new RuntimeException("Database connection timed out"))) // 发送PUT请求并验证响应 Put(s"/rules/$testId") ~> testRoute ~> check { status shouldBe StatusCodes.InternalServerError responseAs[String] shouldBe "connectionFail" } }
3. 测试「更新数据时数据库连接失败」场景
这个场景是findById成功找到数据,但update时连接失败,验证路由的recover分支是否生效:
"return 500 Internal Server Error when database connection fails during update" in { val testId = UUID.randomUUID() val existingRow = RuleRow(testId, test = false) // 先模拟findById成功返回数据 when(mockDatabase.findById(eqTo(testId))) .thenReturn(Future.successful(Some(existingRow))) // 再模拟update方法抛出连接异常 when(mockDatabase.update(eqTo(existingRow.copy(test = true)))) .thenReturn(Future.failed(new RuntimeException("Database connection lost during update"))) Put(s"/rules/$testId") ~> testRoute ~> check { status shouldBe StatusCodes.InternalServerError responseAs[String] shouldBe "updateFail" } } } }
关键注意点
- 一定要用模拟的Database实例,不要连接真实数据库——我们要测试的是路由的错误处理逻辑,而非数据库本身。
- 用Mockito的
thenReturn(Future.failed(...))来模拟异步操作失败,这样路由里的onComplete会进入Failure分支。 - Akka HTTP TestKit的
~>操作符是测试路由的核心:发送请求 → 经过路由 → 检查响应。
内容的提问来源于stack exchange,提问作者Donal Tuohy
相关产品推荐
相关产品推荐

