Every so often I like to have a play around with a part of Junit that I haven’t used before, and I recently decided to look into the TestWatcher API.
I have to admit that I have been meaning to play with this for quite a while now…. I just haven’t really found a good use-case for it. Given that I decided to quit trying to find a good use-case and implement something nerdy instead.
Stretched across the back of the desk in front of me is a BlinkyTape attached to my usb hub. Most of the time the BlinkyTape is just used for a bit of subtle lighting behind my monitor but while looking into the Junit TestWatcher API, it suddenly hit me…. maybe I could combine the two.
I already had a bit of code to interact directly with the BlinkyTape so all I needed to do was figure out how to tracks the success, failure or whether a test is disabled. If I could do that I could then turn the BlinkyTape green, red or orange.
I put together a simple Kotlin implementation of the TestWatcher API that adds a test result status to a list:
class BlinkyTapeTestWatcher : TestWatcher, AfterAllCallback {
private val testResultsStatus = mutableListOf<TestResultStatus>()
override fun testDisabled(context: ExtensionContext, reason: Optional<String>) {
this.testResultsStatus.add(TestResultStatus.DISABLED)
}
override fun testSuccessful(context: ExtensionContext) {
this.testResultsStatus.add(TestResultStatus.SUCCESS)
}
override fun testAborted(context: ExtensionContext, cause: Throwable?) {
this.testResultsStatus.add(TestResultStatus.ABORTED)
}
override fun testFailed(context: ExtensionContext, cause: Throwable?) {
this.testResultsStatus.add(TestResultStatus.FAILED)
}
override fun afterAll(extensionContext: ExtensionContext) {
// first lets check to see if we have any test failures so we can leave the blinky tape as red
if (this.testResultsStatus.any { it == TestResultStatus.FAILED }) {
this.renderFrame(RED_BLINKY_TAPE_FRAME)
return
}
// if no test failures then we can take a look to see if there are any disabled tests. If there are then
// we can set the blinky tape to orange
if (this.testResultsStatus.any { it == TestResultStatus.DISABLED }) {
this.renderFrame(ORANGE_BLINKY_TAPE_FRAME)
return
}
// if no failures or disabled tests then we can set the blinky tape to green
if (this.testResultsStatus.any { it == TestResultStatus.SUCCESS }) {
this.renderFrame(GREEN_BLINKY_TAPE_FRAME)
return
}
}
private fun renderFrame(frame: BlinkyTapeFrame) {
val controller = BlinkyTapeController()
controller.renderFrame(frame)
controller.close()
}
companion object {
val ORANGE_BLINKY_TAPE_FRAME = BlinkyTapeFrame(defaultColour = Color.ORANGE)
val RED_BLINKY_TAPE_FRAME = BlinkyTapeFrame(defaultColour = Color.RED)
val GREEN_BLINKY_TAPE_FRAME = BlinkyTapeFrame(defaultColour = Color.GREEN)
}
private enum class TestResultStatus {
SUCCESS, ABORTED, FAILED, DISABLED
}
}
The BlinkyTapeTestWatcher
class also implements the AfterAllCallback
interface allows us to override a method called afterAll
that is executed when all the tests have finished.
The afterAll
method performs 3 checks:
- If any of the tests have failed it renders the BlinkyTape as all red
- If non of the tests have failed but there were disabled tests it renders the BlinkyTape as all orange
- If all of the tests pass then it renders the BlinkyTape as all green
All in all it seemed to work out pretty well. I uploaded the repo to github if you wanted to play around with this yourself - https://github.com/leeturner/BlinkyTapeTestWatcher
I uploaded a short video of this in action to twitter:
Had a play with the @junitteam TestWatcher API today. Hooked it up to my Blinky Tape LED strip for a visual representation of my test status. Green for all tests passing, red for any failures and orange for all passing but some tests disabled. pic.twitter.com/PezJ0PGb1V
— Lee Turner (@leeturner) March 14, 2021