आपकी इकाई परीक्षण कक्षा को आमतौर पर परीक्षण विधियों के समूह के लिए साझा संसाधन प्रबंधित करने के लिए कुछ चीजों की आवश्यकता होती है। और कोटलिन में आप @BeforeClass
और @AfterClass
परीक्षण कक्षा में नहीं, बल्कि companion object के साथ @JvmStatic
annotation के साथ उपयोग कर सकते हैं।
एक परीक्षण वर्ग की संरचना लगेगा जैसे:
class MyTestClass {
companion object {
init {
// things that may need to be setup before companion class member variables are instantiated
}
// variables you initialize for the class just once:
val someClassVar = initializer()
// variables you initialize for the class later in the @BeforeClass method:
lateinit var someClassLateVar: SomeResource
@BeforeClass @JvmStatic fun setup() {
// things to execute once and keep around for the class
}
@AfterClass @JvmStatic fun teardown() {
// clean up after this class, leave nothing dirty behind
}
}
// variables you initialize per instance of the test class:
val someInstanceVar = initializer()
// variables you initialize per test case later in your @Before methods:
var lateinit someInstanceLateZVar: MyType
@Before fun prepareTest() {
// things to do before each test
}
@After fun cleanupTest() {
// things to do after each test
}
@Test fun testSomething() {
// an actual test case
}
@Test fun testSomethingElse() {
// another test case
}
// ...more test cases
}
ऊपर देखते हुए, आप के बारे में पढ़ा जाना चाहिए:
- companion objects - जावा में क्लास वस्तु के समान है, लेकिन एक सिंगलटन प्रति वर्ग जो स्थिर नहीं है
@JvmStatic
- एक एनोटेशन जो बाहरी वर्ग पर एक स्थिर विधि में एक साथी ऑब्जेक्ट विधि को बदलता है आर जावा इंटरॉप
lateinit
- अनुमति देता है एक var
संपत्ति बाद में प्रारंभ करने के लिए आप एक अच्छी तरह से परिभाषित जीवन चक्र
Delegates.notNull()
है जब - एक संपत्ति है कि कम से कम एक बार पढ़ा जा रहा से पहले स्थापित किया जाना चाहिए के लिए lateinit
के स्थान पर किया जा सकता है।
यहां कोटलिन के लिए परीक्षण कक्षाओं के पूर्ण उदाहरण हैं जो एम्बेडेड संसाधनों का प्रबंधन करते हैं।
पहली बार कॉपी किया गया है और Solr-Undertow tests से संशोधित किया गया है, और परीक्षण के मामलों को चलाने से पहले, एक सोलर-अंडरटेव सर्वर को कॉन्फ़िगर और प्रारंभ करता है। परीक्षण चलाने के बाद, यह परीक्षण द्वारा बनाई गई किसी भी अस्थायी फ़ाइलों को साफ़ करता है। यह सुनिश्चित करता है कि परीक्षण चर से पहले पर्यावरण चर और सिस्टम गुण सही हैं। परीक्षण मामलों के बीच यह किसी अस्थायी लोड किए गए सोलर कोर को उतार देता है। परीक्षण:
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")
// make sure no system properties are set that could interfere with test
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() {
// don't leave any test files behind
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() {
// anything before each test?
}
@After fun cleanupTest() {
// make sure test cores do not bleed over between test cases
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)
}
// ... other test cases
}
और एक और शुरू करने एडब्ल्यूएस DynamoDB एक एम्बेडेड डेटाबेस के रूप में स्थानीय (नकल की और Running AWS DynamoDB-local embedded से थोड़ा संशोधित)।यह परीक्षण java.library.path
को किसी और चीज से पहले या स्थानीय डायनेमोडीबी (बाइनरी लाइब्रेरीज़ के साथ स्क्लाइट का उपयोग करके) चलाने से पहले हैक नहीं करेगा। फिर यह सभी परीक्षण वर्गों के लिए साझा करने के लिए सर्वर शुरू करता है, और परीक्षणों के बीच अस्थायी डेटा को साफ़ करता है। परीक्षण:
class TestAccountManager {
companion object {
init {
// we need to control the "java.library.path" or sqlite cannot find its libraries
val dynLibPath = File("./src/test/dynlib/").absoluteFile
System.setProperty("java.library.path", dynLibPath.toString());
// TEST HACK: if we kill this value in the System classloader, it will be
// recreated on next access allowing java.library.path to be reset
val fieldSysPath = ClassLoader::class.java.getDeclaredField("sys_paths")
fieldSysPath.setAccessible(true)
fieldSysPath.set(null, null)
// ensure logging always goes through Slf4j
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() {
// do not use ServerRunner, it is evil and doesn't set the port correctly, also
// it resets logging to be off.
localDb = DynamoDBProxyServer(localDbPort, LocalDynamoDBServerHandler(
LocalDynamoDBRequestHandler(0, true, null, true, true), null)
)
localDb.start()
// fake credentials are required even though ignored
val auth = BasicAWSCredentials("fakeKey", "fakeSecret")
dbClient = AmazonDynamoDBClient(auth) initializedWith {
signerRegionOverride = "us-east-1"
setEndpoint("http://localhost:$localDbPort")
}
dynamo = DynamoDB(dbClient)
// create the tables once
AccountManagerSchema.createTables(dbClient)
// for debugging reference
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() {
// insert commonly used test data
setupStaticBillingData(dbClient)
}
@After fun cleanupTest() {
// delete anything that shouldn't survive any test case
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)
}
// ...more test cases
}
नोट: उदाहरण के कुछ हिस्सों के साथ ...
JUnit 5 कि उपयोग के मामले के लिए गैर स्थिर तरीकों का समर्थन कर सकते संक्षिप्त कर रहे हैं, को देखने के https://github.com/ जूनिट-टीम/जूनिट 5/अंक/41 9 # मुद्दा -267815529 और कोटलिन डेवलपर्स को इस तरह के सुधारों में रुचि रखने के लिए मेरी टिप्पणी +1 करने में संकोच न करें। –