Lớp kiểm thử đơn vị của bạn thường cần một số thứ để quản lý tài nguyên dùng chung cho một nhóm các phương pháp kiểm tra. Và trong Kotlin, bạn có thể sử dụng @BeforeClass
và @AfterClass
không phải trong lớp thử nghiệm, mà là trong đối tượng đồng hành của nó cùng với @JvmStatic
chú thích .
Cấu trúc của một lớp kiểm tra sẽ giống như sau:
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() {
}
}
Với những điều trên, bạn nên đọc về:
- các đối tượng đồng hành - tương tự như đối tượng Class trong Java, nhưng một singleton trên mỗi lớp không tĩnh
@JvmStatic
- một chú thích biến một phương thức đối tượng đồng hành thành một phương thức tĩnh trên lớp bên ngoài cho Java interop
lateinit
- cho phép một thuộc var
tính được khởi tạo sau này khi bạn có một vòng đời được xác định rõ ràng
Delegates.notNull()
- có thể được sử dụng thay vì lateinit
cho một thuộc tính phải được đặt ít nhất một lần trước khi được đọc.
Dưới đây là các ví dụ đầy đủ hơn về các lớp thử nghiệm cho Kotlin quản lý tài nguyên nhúng.
Đầu tiên được sao chép và sửa đổi từ các bài kiểm tra Solr-Undertow và trước khi các trường hợp kiểm tra được chạy, hãy cấu hình và khởi động máy chủ Solr-Undertow. Sau khi các bài kiểm tra chạy, nó sẽ xóa mọi tệp tạm thời được tạo bởi các bài kiểm tra. Nó cũng đảm bảo các biến môi trường và thuộc tính hệ thống là chính xác trước khi chạy thử nghiệm. Giữa các trường hợp thử nghiệm, nó dỡ bỏ mọi lõi Solr được tải tạm thời. Các bài kiểm tra:
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)
}
}
Và một AWS DynamoDB bắt đầu cục bộ khác dưới dạng cơ sở dữ liệu nhúng (được sao chép và sửa đổi một chút từ Chạy AWS DynamoDB-cục bộ nhúng ). Thử nghiệm này phải hack java.library.path
trước khi bất kỳ điều gì khác xảy ra nếu không DynamoDB cục bộ (sử dụng sqlite với thư viện nhị phân) sẽ không chạy. Sau đó, nó khởi động một máy chủ để chia sẻ cho tất cả các lớp kiểm tra và dọn dẹp dữ liệu tạm thời giữa các lần kiểm tra. Các bài kiểm tra:
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)
}
}
LƯU Ý: một số phần của các ví dụ được viết tắt bằng...