Remove test context from plugin testing framework

This commit is contained in:
Gary Tierney
2017-06-19 17:14:24 +01:00
parent b536b2ed9d
commit b532168551
6 changed files with 106 additions and 135 deletions
+2
View File
@@ -33,6 +33,8 @@ dependencies {
compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion"
compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion" compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion"
// https://mvnrepository.com/artifact/org.hamcrest/hamcrest-all
testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion"
} }
+7 -5
View File
@@ -17,11 +17,7 @@ buildscript {
} }
task testPlugins { task testPlugins {
group = "plugin-verification"
doLast {
println("Finished executing plugin tests")
}
} }
sourceSets { sourceSets {
@@ -95,7 +91,6 @@ def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSourc
binResultsDir = file("$buildDir/plugin-test-results/binary/$name") binResultsDir = file("$buildDir/plugin-test-results/binary/$name")
reports { reports {
html.destination = "$buildDir/reports/plugin-tests/$name"
junitXml.destination = "$buildDir/plugin-tests/$name" junitXml.destination = "$buildDir/plugin-tests/$name"
} }
@@ -206,3 +201,10 @@ pluginMap.values().each {
configurePluginDependencies(it.mainSources, it.testSources, dependencies) configurePluginDependencies(it.mainSources, it.testSources, dependencies)
configurePluginTasks(it.normalizedName, it.mainSources, it.testSources, it.scriptFiles, dependencies) configurePluginTasks(it.normalizedName, it.mainSources, it.testSources, it.scriptFiles, dependencies)
} }
task testPluginsReport(type: TestReport) {
destinationDir = file("$buildDir/reports/plugin-tests")
reportOn tasks.findAll { it.group.equals("plugin-verification"); }
}
testPlugins.finalizedBy testPluginsReport
@@ -1,21 +1,26 @@
package org.apollo.game.plugins.testing package org.apollo.game.plugins.testing
import org.apollo.cache.def.NpcDefinition
import org.apollo.game.action.Action
import org.apollo.game.message.handler.MessageHandler import org.apollo.game.message.handler.MessageHandler
import org.apollo.game.message.handler.MessageHandlerChainSet import org.apollo.game.message.handler.MessageHandlerChainSet
import org.apollo.game.model.Position import org.apollo.game.message.impl.*
import org.apollo.game.model.World import org.apollo.game.model.*
import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.*
import org.apollo.game.model.entity.obj.GameObject
import org.apollo.game.model.entity.obj.StaticGameObject
import org.apollo.game.plugin.* import org.apollo.game.plugin.*
import org.apollo.net.message.Message import org.apollo.net.message.Message
import org.apollo.util.security.PlayerCredentials import org.apollo.util.security.PlayerCredentials
import org.junit.After import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Matchers.any import org.mockito.Matchers.any
import org.mockito.Mockito.mock import org.mockito.Mockito
import org.mockito.invocation.InvocationOnMock import org.mockito.invocation.InvocationOnMock
import org.mockito.stubbing.Answer import org.mockito.stubbing.Answer
import org.powermock.api.mockito.PowerMockito.spy import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner import org.powermock.modules.junit4.PowerMockRunner
import java.util.* import java.util.*
@@ -23,24 +28,22 @@ import java.util.*
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest(World::class, PluginContext::class, Player::class) @PrepareForTest(World::class, PluginContext::class, Player::class)
abstract class KotlinPluginTest { abstract class KotlinPluginTest {
private var ctx: KotlinPluginTestContext? = null lateinit var world: World
lateinit var player: Player
protected fun context(): KotlinPluginTestContext { lateinit var messageHandlers: MessageHandlerChainSet
return ctx ?: throw IllegalStateException("Setup method not called")
}
@Before @Before
fun setup() { fun setup() {
val messageHandlerChainSet = MessageHandlerChainSet() messageHandlers = MessageHandlerChainSet()
val world = spy<World>(World()) world = PowerMockito.spy(World())
val answer = Answer<Any?> { invocation: InvocationOnMock -> val answer = Answer<Any?> { invocation: InvocationOnMock ->
messageHandlerChainSet.putHandler( messageHandlers.putHandler(
invocation.arguments[0] as Class<Message>, invocation.arguments[0] as Class<Message>,
invocation.arguments[1] as MessageHandler<*>) invocation.arguments[1] as MessageHandler<*>)
} }
val pluginContext = mock<PluginContext>(PluginContext::class.java, answer) val pluginContext = PowerMockito.mock<PluginContext>(PluginContext::class.java, answer)
val pluginEnvironment = KotlinPluginEnvironment(world) val pluginEnvironment = KotlinPluginEnvironment(world)
pluginEnvironment.setContext(pluginContext) pluginEnvironment.setContext(pluginContext)
@@ -48,21 +51,63 @@ abstract class KotlinPluginTest {
val credentials = PlayerCredentials("test", "test", 1, 1, "0.0.0.0") val credentials = PlayerCredentials("test", "test", 1, 1, "0.0.0.0")
val position = Position(3200, 3200, 0) val position = Position(3200, 3200, 0)
val player = spy<Player>(Player(world, credentials, position))
org.powermock.api.mockito.PowerMockito.doNothing().`when`(player).send(any<Message>())
world.register(player)
val region = world.regionRepository.fromPosition(position) val region = world.regionRepository.fromPosition(position)
player = PowerMockito.spy(Player(world, credentials, position))
world.register(player)
region.addEntity(player) region.addEntity(player)
ctx = KotlinPluginTestContext(world, player, messageHandlerChainSet) PowerMockito.doNothing().`when`(player).send(any())
} }
@After fun interactWith(entity: Entity, option: Int = 1) {
fun destroy() { player.position = entity.position.step(1, Direction.NORTH)
ctx!!.shutdown()
when (entity) {
is GameObject -> notify(ObjectActionMessage(option, entity.id, entity.position))
is Npc -> notify(NpcActionMessage(option, entity.index))
is Player -> notify(PlayerActionMessage(option, entity.index))
}
}
fun spawnNpc(id: Int, position: Position): Npc {
val definition = NpcDefinition(id)
val npc = Npc(world, position, definition, arrayOfNulls(4))
val region = world.regionRepository.fromPosition(position)
val npcs = world.npcRepository
npcs.add(npc)
region.addEntity(npc)
return npc
}
fun spawnObject(id: Int, position: Position): GameObject {
val obj = StaticGameObject(world, id, position, 0, 0)
world.spawn(obj)
return obj
}
fun notify(message: Message) {
messageHandlers.notify(player, message)
}
fun waitForActionCompletion(predicate: (Action<Player>) -> Boolean = { _ -> true }, timeout: Int = 15) {
val actionCaptor: ArgumentCaptor<Action<*>> = ArgumentCaptor.forClass(Action::class.java)
Mockito.verify(player).startAction(actionCaptor.capture())
val action: Action<Player> = actionCaptor.value as Action<Player>
Assert.assertTrue("Found wrong action type", predicate.invoke(action))
var pulses = 0
do {
action.pulse()
} while (action.isRunning && pulses++ < timeout)
Assert.assertFalse("Exceeded timeout waiting for action completion", pulses > timeout)
} }
} }
@@ -1,74 +0,0 @@
package org.apollo.game.plugins.testing
import org.apollo.cache.def.NpcDefinition
import org.apollo.game.action.Action
import org.apollo.game.message.handler.MessageHandlerChainSet
import org.apollo.game.message.impl.*
import org.apollo.game.model.*
import org.apollo.game.model.entity.*
import org.apollo.game.model.entity.obj.GameObject
import org.apollo.game.model.entity.obj.StaticGameObject
import org.apollo.net.message.Message
import org.junit.Assert
import org.mockito.ArgumentCaptor
import org.mockito.Mockito
class KotlinPluginTestContext(val world: World, val activePlayer: Player, val messageHandlers: MessageHandlerChainSet) {
fun interactWith(entity: Entity, option: Int = 1) {
activePlayer.position = entity.position.step(1, Direction.NORTH)
when (entity) {
is GameObject -> notify(ObjectActionMessage(option, entity.id, entity.position))
is Npc -> notify(NpcActionMessage(option, entity.index))
is Player -> notify(PlayerActionMessage(option, entity.index))
}
}
fun spawnNpc(id: Int, position: Position): Npc {
val definition = NpcDefinition(id)
val npc = Npc(world, position, definition, arrayOfNulls(4))
val region = world.regionRepository.fromPosition(position)
val npcs = world.npcRepository
world.register(npc)
npcs.add(npc)
region.addEntity(npc)
return npc
}
fun spawnObject(id: Int, position: Position): GameObject {
val obj = StaticGameObject(world, id, position, 0, 0)
world.spawn(obj)
return obj
}
fun notify(message: Message) {
messageHandlers.notify(activePlayer, message)
}
fun shutdown() {
}
fun waitForActionCompletion(predicate: (Action<Player>) -> Boolean = { _ -> true }, timeout: Int = 15) {
val actionCaptor: ArgumentCaptor<Action<*>> = ArgumentCaptor.forClass(Action::class.java)
Mockito.verify(activePlayer).startAction(actionCaptor.capture())
val action: Action<Player> = actionCaptor.value as Action<Player>
Assert.assertTrue("Found wrong action type", predicate.invoke(action))
var pulses = 0
do {
action.pulse()
} while (action.isRunning && pulses++ < timeout)
Assert.assertFalse("Exceeded timeout waiting for action completion", pulses > timeout)
}
}
+8 -10
View File
@@ -14,25 +14,23 @@ class OpenBankTest() : KotlinPluginTest() {
@Test @Test
fun `Interacting with a bank teller should open the players bank`() { fun `Interacting with a bank teller should open the players bank`() {
val ctx = context() val bankTeller = spawnNpc(BANK_TELLER_ID, BANK_POSITION)
val bankTeller = ctx.spawnNpc(BANK_TELLER_ID, BANK_POSITION)
// @todo - these option numbers only match by coincidence, we should be looking up the correct ones // @todo - these option numbers only match by coincidence, we should be looking up the correct ones
ctx.interactWith(bankTeller, option = 2) interactWith(bankTeller, option = 2)
ctx.waitForActionCompletion() waitForActionCompletion()
verify(ctx.activePlayer).openBank() verify(player).openBank()
} }
@Test @Test
fun `Interacting with a bank booth object should open the players bank`() { fun `Interacting with a bank booth object should open the players bank`() {
val ctx = context() val bankBooth = spawnObject(BANK_BOOTH_ID, BANK_POSITION)
val bankBooth = ctx.spawnObject(BANK_BOOTH_ID, BANK_POSITION)
ctx.interactWith(bankBooth, option = 2) interactWith(bankBooth, option = 2)
ctx.waitForActionCompletion() waitForActionCompletion()
verify(ctx.activePlayer).openBank() verify(player).openBank()
} }
} }
@@ -1,12 +1,10 @@
import org.apollo.game.model.Position import org.apollo.game.model.Position
import org.apollo.game.model.entity.Skill import org.apollo.game.model.entity.Skill
import org.apollo.game.model.entity.SkillSet
import org.apollo.game.plugins.testing.KotlinPluginTest import org.apollo.game.plugins.testing.KotlinPluginTest
import org.junit.Assert.assertTrue import org.hamcrest.Matchers.*
import org.junit.Assert.*
import org.junit.Test import org.junit.Test
import org.mockito.Matchers import org.mockito.Mockito.*
import org.mockito.Matchers.*
import org.mockito.Mockito.verify
class TrainingDummyTest : KotlinPluginTest() { class TrainingDummyTest : KotlinPluginTest() {
@@ -16,30 +14,30 @@ class TrainingDummyTest : KotlinPluginTest() {
} }
@Test fun `Hitting the training dummy should give the player attack experience`() { @Test fun `Hitting the training dummy should give the player attack experience`() {
val ctx = context() val dummy = spawnObject(DUMMY_ID, DUMMY_POSITION)
val dummy = ctx.spawnObject(DUMMY_ID, DUMMY_POSITION) val skills = player.skillSet
val skills = ctx.activePlayer.skillSet val beforeExp = skills.getExperience(Skill.ATTACK)
val attackExp = skills.getExperience(Skill.ATTACK)
ctx.interactWith(dummy, option = 2) interactWith(dummy, option = 2)
ctx.waitForActionCompletion() waitForActionCompletion()
assertTrue("Did not gain exp after hitting dummy", skills.getExperience(Skill.ATTACK) > attackExp) val afterExp = skills.getExperience(Skill.ATTACK)
assertThat(afterExp, greaterThan(beforeExp))
} }
@Test fun `The player should stop getting attack experience from the training dummy at level 8`() { @Test fun `The player should stop getting attack experience from the training dummy at level 8`() {
val ctx = context() val dummy = spawnObject(DUMMY_ID, DUMMY_POSITION)
val skills = player.skillSet
val dummy = ctx.spawnObject(DUMMY_ID, DUMMY_POSITION)
val skills = ctx.activePlayer.skillSet
skills.setMaximumLevel(Skill.ATTACK, 8) skills.setMaximumLevel(Skill.ATTACK, 8)
val attackExp = skills.getExperience(Skill.ATTACK) val beforeExp = skills.getExperience(Skill.ATTACK)
ctx.interactWith(dummy, option = 2) interactWith(dummy, option = 2)
ctx.waitForActionCompletion() waitForActionCompletion()
verify(ctx.activePlayer).sendMessage(contains("nothing more you can learn")) val afterExp = skills.getExperience(Skill.ATTACK)
assertTrue("Attack exp has changed since hitting the dummy", attackExp == skills.getExperience(Skill.ATTACK))
verify(player).sendMessage(contains("nothing more you can learn"))
assertThat(afterExp, equalTo(beforeExp))
} }
} }