ชั้นทดสอบหน่วยของคุณมักต้องการบางสิ่งเพื่อจัดการทรัพยากรที่ใช้ร่วมกันสำหรับกลุ่มวิธีการทดสอบ และใน Kotlin คุณสามารถใช้@BeforeClass
และ@AfterClass
ไม่ได้อยู่ในระดับการทดสอบ แต่ภายในของวัตถุสหายพร้อมกับคำอธิบายประกอบ@JvmStatic
โครงสร้างของคลาสทดสอบจะมีลักษณะดังนี้:
class MyTestClass {
companion object {
init {
}
val someClassVar = initializer()
lateinit var someClassLateVar: SomeResource
@BeforeClass @JvmStatic fun setup() {
}
@AfterClass @JvmStatic fun teardown() {
}
}
val someInstanceVar = initializer()
var lateinit someInstanceLateZVar: MyType
@Before fun prepareTest() {
}
@After fun cleanupTest() {
}
@Test fun testSomething() {
}
@Test fun testSomethingElse() {
}
}
จากที่กล่าวมาคุณควรอ่านเกี่ยวกับ:
- วัตถุร่วม - คล้ายกับคลาสอ็อบเจ็กต์ใน Java แต่เป็นซิงเกิลตันต่อคลาสที่ไม่คงที่
@JvmStatic
- คำอธิบายประกอบที่เปลี่ยนเมธอดอ็อบเจ็กต์ที่แสดงร่วมเป็นวิธีการแบบคงที่บนคลาสภายนอกสำหรับการทำงานร่วมกันของ Java
lateinit
- อนุญาตให้var
เริ่มต้นคุณสมบัติในภายหลังเมื่อคุณมีวงจรชีวิตที่กำหนดไว้อย่างดี
Delegates.notNull()
- สามารถใช้แทนlateinit
คุณสมบัติที่ควรตั้งค่าอย่างน้อยหนึ่งครั้งก่อนที่จะอ่าน
ต่อไปนี้เป็นตัวอย่างคลาสทดสอบสำหรับ Kotlin ที่จัดการทรัพยากรแบบฝัง
ขั้นแรกถูกคัดลอกและแก้ไขจากการทดสอบ Solr-Undertowและก่อนที่จะรันกรณีทดสอบให้กำหนดค่าและเริ่มเซิร์ฟเวอร์ Solr-Undertow หลังจากการทดสอบดำเนินการจะล้างไฟล์ชั่วคราวที่สร้างโดยการทดสอบ นอกจากนี้ยังช่วยให้แน่ใจว่าตัวแปรสภาพแวดล้อมและคุณสมบัติของระบบถูกต้องก่อนที่จะดำเนินการทดสอบ ระหว่างกรณีทดสอบจะยกเลิกการโหลดคอร์ Solr ที่โหลดชั่วคราว การทดสอบ:
class TestServerWithPlugin {
companion object {
val workingDir = Paths.get("test-data/solr-standalone").toAbsolutePath()
val coreWithPluginDir = workingDir.resolve("plugin-test/collection1")
lateinit var server: Server
@BeforeClass @JvmStatic fun setup() {
assertTrue(coreWithPluginDir.exists(), "test core w/plugin does not exist $coreWithPluginDir")
resetEnvProxy()
cleanSysProps()
routeJbossLoggingToSlf4j()
cleanFiles()
val config = mapOf(...)
val configLoader = ServerConfigFromOverridesAndReference(workingDir, config) verifiedBy { loader ->
...
}
assertNotNull(System.getProperty("solr.solr.home"))
server = Server(configLoader)
val (serverStarted, message) = server.run()
if (!serverStarted) {
fail("Server not started: '$message'")
}
}
@AfterClass @JvmStatic fun teardown() {
server.shutdown()
cleanFiles()
resetEnvProxy()
cleanSysProps()
}
private fun cleanSysProps() { ... }
private fun cleanFiles() {
coreWithPluginDir.resolve("data").deleteRecursively()
Files.deleteIfExists(coreWithPluginDir.resolve("core.properties"))
Files.deleteIfExists(coreWithPluginDir.resolve("core.properties.unloaded"))
}
}
val adminClient: SolrClient = HttpSolrClient("http://localhost:8983/solr/")
@Before fun prepareTest() {
}
@After fun cleanupTest() {
unloadCoreIfExists("tempCollection1")
unloadCoreIfExists("tempCollection2")
unloadCoreIfExists("tempCollection3")
}
private fun unloadCoreIfExists(name: String) { ... }
@Test
fun testServerLoadsPlugin() {
println("Loading core 'withplugin' from dir ${coreWithPluginDir.toString()}")
val response = CoreAdminRequest.createCore("tempCollection1", coreWithPluginDir.toString(), adminClient)
assertEquals(0, response.status)
}
}
และอีกตัวเริ่มต้น AWS DynamoDB ภายในเป็นฐานข้อมูลแบบฝัง (คัดลอกและแก้ไขเล็กน้อยจากการเรียกใช้ AWS DynamoDB-local แบบฝัง ) การทดสอบนี้ต้องแฮ็คjava.library.path
ก่อนที่จะเกิดอะไรขึ้นมิฉะนั้น DynamoDB ในเครื่อง (โดยใช้ sqlite กับไบนารีไลบรารี) จะไม่ทำงาน จากนั้นจะเริ่มเซิร์ฟเวอร์เพื่อแชร์สำหรับคลาสทดสอบทั้งหมดและล้างข้อมูลชั่วคราวระหว่างการทดสอบ การทดสอบ:
class TestAccountManager {
companion object {
init {
val dynLibPath = File("./src/test/dynlib/").absoluteFile
System.setProperty("java.library.path", dynLibPath.toString());
val fieldSysPath = ClassLoader::class.java.getDeclaredField("sys_paths")
fieldSysPath.setAccessible(true)
fieldSysPath.set(null, null)
System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.Slf4jLog")
}
private val localDbPort = 19444
private lateinit var localDb: DynamoDBProxyServer
private lateinit var dbClient: AmazonDynamoDBClient
private lateinit var dynamo: DynamoDB
@BeforeClass @JvmStatic fun setup() {
localDb = DynamoDBProxyServer(localDbPort, LocalDynamoDBServerHandler(
LocalDynamoDBRequestHandler(0, true, null, true, true), null)
)
localDb.start()
val auth = BasicAWSCredentials("fakeKey", "fakeSecret")
dbClient = AmazonDynamoDBClient(auth) initializedWith {
signerRegionOverride = "us-east-1"
setEndpoint("http://localhost:$localDbPort")
}
dynamo = DynamoDB(dbClient)
AccountManagerSchema.createTables(dbClient)
dynamo.listTables().forEach { table ->
println(table.tableName)
}
}
@AfterClass @JvmStatic fun teardown() {
dbClient.shutdown()
localDb.stop()
}
}
val jsonMapper = jacksonObjectMapper()
val dynamoMapper: DynamoDBMapper = DynamoDBMapper(dbClient)
@Before fun prepareTest() {
setupStaticBillingData(dbClient)
}
@After fun cleanupTest() {
deleteAllInTable<Account>()
deleteAllInTable<Organization>()
deleteAllInTable<Billing>()
}
private inline fun <reified T: Any> deleteAllInTable() { ... }
@Test fun testAccountJsonRoundTrip() {
val acct = Account("123", ...)
dynamoMapper.save(acct)
val item = dynamo.getTable("Accounts").getItem("id", "123")
val acctReadJson = jsonMapper.readValue<Account>(item.toJSON())
assertEquals(acct, acctReadJson)
}
}
หมายเหตุ:บางส่วนของตัวอย่างย่อด้วย...