The Kaptain on … stuff

08 Apr, 2009

Griffon SwingX Fest testing

Posted by: TheKaptain In: Development

This is the third installment of my Griffon SwingSet experiment. If you’re coming late to the party (and would like to know just what the heck I’m talking about) you can catch up by reading this and this.

So the SwingX demo has 3 sliders that affect integer values on the JXBusyLabel. Using the Groovy ‘bind’ syntax, responding to changes in these events is simple to say the least.

And as promised in the last post, I’ve written some FEST tests to validate that everything is working as expected. Stay tuned to the end of the post to see a video of the running tests 🙂

FEST provides some convenience wrappers for UI elements that allows easy access to common operations. Looking up a JSlider in the UI for instance, returns a JSliderFixture object with a nice little ‘slideTo’ method.
First off, here are the UI components under test. Yes, this is the entire code, including all necessary wiring to trigger updates automagically as the sliders are changed.

speedSlider = slider(
        name: 'speedSlider',
        sliderModel: boundedRangeModel(
                min: 1, max: model.SPEED_MAX - 1, value: model.SPEED_MAX - 1, extent: 0),
        opaque: true)

slider = slider(
        name: 'slider',
        sliderModel: boundedRangeModel(
                min: 1, max: 50, value: 8, extent: 0), opaque: true)

tSlider = slider(
        name: 'tSlider',
        sliderModel: boundedRangeModel(
                min: 1, max: 20, value: 4, extent: 0), opaque: true)

label = jxbusyLabel(name: 'busyLabel',
        preferredSize: new Dimension(model.W / 2 as int, model.H / 2 as int),
        busyPainter: busyPainter(
                highlightColor: bind { model.busyColor }, baseColor: bind {model.baseColor},
                points: bind{slider.value}, trailLength: bind{tSlider.value}),
        opaque: false,
        horizontalAlignment: JLabel.CENTER,
        delay: bind{speedSlider.value})
........
buttons.addLine(button(name: model.START_NAME, action:startAction))

And then the tests run against them. Each test moves a slider sequentially from the minimum to the maximum values and checks at each change to ensure that the same change is reflected on the bound JXBusyLabel property. Because the JXBusyLabel does not have a ready corresponding FEST built in fixture class, we just look it up as a Component by inspecting the UI for the appropriate named Component. The Groovy dynamic type system makes accessing its internal properties trivial after that.

/**
   * Start the animation and then ensure that changing the speed slider changes the delay.
   */
   @Test void testSpeedSlider() {
     def button = window.button(JXBusyLabelDemoModel.START_NAME)
     button.click()
     def JSliderFixture slider = window.slider('speedSlider')
     ComponentFinder finder = BasicComponentFinder.finderWithCurrentAwtHierarchy();
     def busyLabel = finder.findByName(app.appFrames[0], 'busyLabel')
     Assert.assertNotNull(slider)
     Assert.assertNotNull(busyLabel)
     (1..JXBusyLabelDemoModel.SPEED_MAX - 1).each { speed ->
       slider.slideTo(speed)
       Assert.assertEquals(busyLabel.delay, speed)
     }
   }

  /**
   * Start the animation and then ensure that changing the points slider changes the
   * number of points.
   */
   @Test void testPointsSlider() {
     def button = window.button(JXBusyLabelDemoModel.START_NAME)
     button.click()
     def JSliderFixture slider = window.slider('slider')
     ComponentFinder finder = BasicComponentFinder.finderWithCurrentAwtHierarchy();
     def busyLabel = finder.findByName(app.appFrames[0], 'busyLabel')
     Assert.assertNotNull(slider)
     Assert.assertNotNull(busyLabel)
     (1..50).each { points ->
       slider.slideTo(points)
       Assert.assertEquals(busyLabel.busyPainter.points, points)
     }
   }

  /**
   * Start the animation and then ensure that changing the trail slider changes
   * the trailLength.
   */
   @Test void testTrailSlider() {
     def button = window.button(JXBusyLabelDemoModel.START_NAME)
     button.click()
     def JSliderFixture slider = window.slider('tSlider')
     ComponentFinder finder = BasicComponentFinder.finderWithCurrentAwtHierarchy();
     def busyLabel = finder.findByName(app.appFrames[0], 'busyLabel')
     Assert.assertNotNull(slider)
     Assert.assertNotNull(busyLabel)
     (1..20).each { trailLength ->
       slider.slideTo(trailLength)
       Assert.assertEquals(busyLabel.busyPainter.trailLength, trailLength)
     }
   }

It’s particular amusing to note that the test code is more verbose than the Swing component setup. Man, after all of the Swing code I’ve written, WHY WAS NONE OF IT EVER THIS EASY!
Sorry for the shouting, but it’s late and updating this code to use binding instead of change listeners AND writing the tests AND writing this blog post took all of about 45 minutes. So you’ll have to forgive me for getting excited and all.

Here is the promised video showing the FEST test suite being run.. Give it a second as the first round of tests(not shown in the code above) do a bunch of assertions to make sure that all of the expected Components can be found. Not terribly interesting to watch, but a great win for Java GUI testing!

Share
Get Adobe Flash player