Scala 在每个测试函数之后运行不同的代码
我正在编写与数据库交互的测试,并希望针对每个测试进行某种设置和拆卸。这就是我目前拥有的:Scala 在每个测试函数之后运行不同的代码,scala,playframework,Scala,Playframework,我正在编写与数据库交互的测试,并希望针对每个测试进行某种设置和拆卸。这就是我目前拥有的: "my test" in { // Use anorm to populate the database Db.withConnection { SQL"INSERT INTO ...".execute() // Do some tests foo must equal 1 bar must equal 2
"my test" in {
// Use anorm to populate the database
Db.withConnection {
SQL"INSERT INTO ...".execute()
// Do some tests
foo must equal 1
bar must equal 2
// Remove the test data
SQL"DELETE FROM ...".execute()
}
}
这种方法的问题是,如果其中一个测试失败,那么执行就会停止,测试数据永远不会从数据库中删除。假设您使用的是specs2,您可以为每个测试创建一个
范围:
"my test" in DatabaseSetup {
// Do some tests
foo must equal 1
bar must equal 2
}
trait DatabaseSetup extends org.specs2.mutable.Around {
def around[T: org.specs2.execute.AsResult](t: => T) = {
Db.withConnection {
// Insert data
}
val result = org.specs2.execute.AsResult(t)
Db.withConnection {
// Remove data
}
result
}
}
import anorm._
import org.scalatest.{BeforeAndAfter, DoNotDiscover}
import org.scalatestplus.play.{ConfiguredServer, PlaySpec}
import play.api.db.DB
import play.api.libs.json.Json
import play.api.libs.ws.WS
import play.api.test.Helpers._
@DoNotDiscover
class ExampleSpec extends PlaySpec with BeforeAndAfter with ConfiguredServer {
val baseAddress = s"http://localhost:$testServerPort/"
var rowID: Int = _
before {
DB.withConnection { implicit connection =>
rowID = SQL"INSERT INTO some_table (col1, col2) VALUES('v1', 'v2')".executeInsert(SqlParser.scalar[Int].single)
}
}
after {
DB.withConnection { implicit connection =>
SQL"DELETE FROM some_table WHERE id = $rowID".execute()
}
}
"GET my/endpoint/{id}" should {
"return a 200" in {
val address = baseAddress + s"my/endpoint/$rowID"
val response = await(WS.url(address).get())
response.status mustEqual OK
}
}
}
无论如何,这可能很难维护,而且这种结构可能会暴露出生产代码或测试代码的一些问题。您应该问问自己,为什么不能重用数据库设置。@marcospereira的答案适用于使用specs2
进行测试的情况,但我使用的是PlaySpec
。下面是一个例子:
在数据库中插入一行
设置rowID
,以便它可以在其他任何地方使用
根据rowID
,向服务器发出GET请求
测试结果,
从数据库中删除相应的行
import anorm._
import org.scalatest.{BeforeAndAfter, DoNotDiscover}
import org.scalatestplus.play.{ConfiguredServer, PlaySpec}
import play.api.db.DB
import play.api.libs.json.Json
import play.api.libs.ws.WS
import play.api.test.Helpers._
@DoNotDiscover
class ExampleSpec extends PlaySpec with BeforeAndAfter with ConfiguredServer {
val baseAddress = s"http://localhost:$testServerPort/"
var rowID: Int = _
before {
DB.withConnection { implicit connection =>
rowID = SQL"INSERT INTO some_table (col1, col2) VALUES('v1', 'v2')".executeInsert(SqlParser.scalar[Int].single)
}
}
after {
DB.withConnection { implicit connection =>
SQL"DELETE FROM some_table WHERE id = $rowID".execute()
}
}
"GET my/endpoint/{id}" should {
"return a 200" in {
val address = baseAddress + s"my/endpoint/$rowID"
val response = await(WS.url(address).get())
response.status mustEqual OK
}
}
}
我的应用程序是一个RESTAPI,所以我只想通过在数据库中放入一些数据来测试端点,然后点击端点(我知道会发生什么,因为我刚刚放入了数据),然后删除这些数据,这样我就不会污染任何其他测试。有更好的方法吗?如果测试集中在一个资源上,我不明白为什么每个测试“方法”都需要不同的设置。我的意思是,如果你有PersonApiSpec
,CountryApiSpec
,LessonApiSpec
,等等,我想这会给你足够的隔离。当然,这个观点是基于我可以从这个问题中推断出来的。:-)无论如何,我的答案中的环绕特征可以用于这两种情况。