La tua classe di unit test di solito ha bisogno di alcune cose per gestire una risorsa condivisa per un gruppo di metodi di test. E in Kotlin puoi usare @BeforeClass
e @AfterClass
non nella classe di test, ma piuttosto all'interno del suo oggetto associato insieme @JvmStatic
all'annotazione .
La struttura di una classe di test sarebbe simile a:
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() {
}
}
Dato quanto sopra, dovresti leggere su:
- oggetti companion - simili all'oggetto Class in Java, ma un singleton per classe che non è statico
@JvmStatic
- un'annotazione che trasforma un metodo oggetto compagno in un metodo statico sulla classe esterna per l'interoperabilità Java
lateinit
- consente var
di inizializzare una proprietà in un secondo momento quando si dispone di un ciclo di vita ben definito
Delegates.notNull()
- può essere utilizzato al posto di lateinit
una proprietà che dovrebbe essere impostata almeno una volta prima di essere letta.
Di seguito sono riportati esempi più completi di classi di test per Kotlin che gestiscono le risorse incorporate.
Il primo viene copiato e modificato dai test Solr-Undertow e prima che i casi di test vengano eseguiti, configura e avvia un server Solr-Undertow. Dopo l'esecuzione dei test, elimina tutti i file temporanei creati dai test. Garantisce inoltre che le variabili di ambiente e le proprietà di sistema siano corrette prima dell'esecuzione dei test. Tra i casi di test, scarica tutti i core Solr caricati temporaneamente. Il test:
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)
}
}
E un altro avvio di AWS DynamoDB locale come database incorporato (copiato e leggermente modificato da Running AWS DynamoDB-local embedded ). Questo test deve hackerare il java.library.path
prima che accada qualsiasi altra cosa o DynamoDB locale (utilizzando sqlite con le librerie binarie) non verrà eseguito. Quindi avvia un server da condividere per tutte le classi di test e pulisce i dati temporanei tra i test. Il test:
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)
}
}
NOTA: alcune parti degli esempi sono abbreviate con...