我注意到在将我的TornadoFX版本从1.7.12升级到1.7.14时,我的一个测试破了。当被测runAsyncWithProgress
中的View
被状态为ThreadPoolExecutor
的{{1}}拒绝时,事情似乎就会失控。我在1.7.13的发行说明中看到有一个更改“内部线程池在应用程序退出时关闭”。将TornadoFX版本设置为1.7.13导致同样的失败,这证实了我怀疑它与上述变化有关。
我写了一个简单的应用程序来演示这个错误。
Terminated
和测试
// src/main/kotlin/me/carltonwhitehead/AsyncBugApp.kt
class AsyncBugApp : App(MainView::class)
/**
* The main method is needed to support the mvn jfx:run goal.
*/
fun main(args: Array<String>) {
Application.launch(AsyncBugApp::class.java, *args)
}
class MainView : View("Async Bug App") {
val controller: MainController by inject()
override val root = pane {
button("Robot-click to repeat bug") {
id = "bug"
action {
runAsync {
controller.onAction("button clicked")
}
}
}
}
}
class MainController : Controller() {
fun onAction(message: String) {
println(message)
}
}
第一次执行测试时,它会通过。第二次,它会挂起,因为runAsync被以下堆栈跟踪拒绝。
// src/test/kotlin/me/carltonwhitehead/AsyncBugAppTest.kt
@RunWith(Parameterized::class)
class AsyncBugAppTest(val rounds: Int) {
companion object {
@JvmStatic
@Parameterized.Parameters
fun data() : Collection<Array<Int>> {
return listOf(arrayOf(1), arrayOf(1))
}
}
lateinit var robot: FxRobot
lateinit var app: App
@RelaxedMockK
lateinit var controller: MainController
@Rule @JvmField
val timeout = Timeout(10, TimeUnit.SECONDS)
@Before
fun before() {
MockKAnnotations.init(this)
FxToolkit.registerPrimaryStage()
app = AsyncBugApp()
app.scope.set(controller)
FxToolkit.setupApplication { app }
robot = FxRobot()
println("rounds = $rounds")
}
@After
fun after() {
FxToolkit.cleanupStages()
FxToolkit.cleanupApplication(app)
}
@Test()
fun itShouldSurviveRunAsyncMultipleTimes() {
val latch = CountDownLatch(rounds)
every { controller.onAction(any()) }.answers { latch.countDown() }
var i = 0
while(i <= rounds) {
robot.clickOn("#bug")
i++
}
latch.await()
verify(exactly = rounds) { controller.onAction(any()) }
}
}
我怀疑我可能在TestFX / TornadoFX应用程序生命周期中出错了。每个测试周期都在创建一个新的app实例,所以我很困惑为什么会保留ThreadPoolExecutor。有什么建议吗?