Hardcore unit testing in Swing

I’m doing some Swing stuff in my Copious Free Time, basically for fun but also to scratch an old itch. I’m committing myself to high percentages of test coverage (ideally 100%, but I’d sign up for everything above 80%), and this is a good exercise for my rusty Swing skills.

Tonight I spent more than a fair amount of time trying to test a JTextField on which I’m attaching a custom key listener (I want it to accept just digits): of course setText() doesn’t work since it bypasses the key listener code, so I figured out I had to basically emulate the keyboard behaviour. From a first cursory look I thought it would be as easy as sending the key events to the widget via Component.dispatchEvent(), but I found out the hard way that this wasn’t the case, since my widget wasn’t receiving anything. A googling session showed me what my mistake was, and in the end I had to enter the treacherous hallways of AWT focus management, having learnt that a Component won’t receive any key events unless focused (well, I assume that’s just fair enough).

Unfortunately I have been unable to programmatically set the focus on the component I wanted to test: a Component won’t receive any focus unless it’s displayable, and setting displayability on a widget by hand is not an easy task. Ultimately I had to pack my widget into a frame in order to have AWT do the gruntwork for me: the good news is that my textfield works as expected and my bar is green again, but still I don’t like having a Swing window popping up on every test run. Sure, I could probably use headless AWT to hide it, but if any Swing savy geek drops by this entry I could definitely use some assistance in solving this issue in a better way.

Update: thanks to Adrian Sutton I have a much better solution now. The only problem with Adrian’s solution was the focusManagerIsDispatching field belonging to AWTEvent and being private, so the revised solution is:

    public void simulateKey(KeyEvent e, Component c) throws Exception {
        Field[] fields = AWTEvent.class.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
           if ("focusManagerIsDispatching".equals(fields[i].getName())) {
              fields[i].setAccessible(true);
              fields[i].set(e, Boolean.TRUE);
              c.dispatchEvent(e);
           }
        }
     }

Thanks so much Adrian!

Comments

comments

6 thoughts on “Hardcore unit testing in Swing”

  1. If you want to restrict the data for a component, it is much better to alter the model than the component itself.

    In this case adding a document filter to a document is easy enough. It’s much easier to test. It frees the original component to be subclassed on basis of other variations. The filtered document can be used with other types of component.

  2. How To Simulate Key Events In Swing JUnit Tests
    Gianugo Rabellino has been playing with unit testing in Swing – an area that I’ve spent a lot of time complaining about in the past.  In his particular case he’s trying to send key events to Swing components programmatically so…

  3. How To Simulate Key Events In Swing JUnit Tests
    Gianugo Rabellino has been playing with unit testing in Swing – an area that I’ve spent a lot of time complaining about in the past.  In his particular case he’s trying to send key events to Swing components programmatically so…

  4. Hi Gianugo!

    I’m no savvy guru here, just remembered java.awt.Robot class, perhaps it could be of some use. My uneducated feeling is that sadly we’re bound to actually make our components appear on screen for testing :-(

Comments are closed.