162

The calculations in my code are well-tested, but because there is so much GUI code, my overall code coverage is lower than I'd like. Are there any guidelines on unit-testing GUI code? Does it even make sense?

For example, there are graphs in my app. I haven't been able to figure out how to automate the testing of the graphs. It takes a human eye, AFAIK, to check if the graph is correct.

(I'm using Java Swing)

Gary Barrett
  • 1,764
  • 5
  • 21
  • 33
Steve McLeod
  • 51,737
  • 47
  • 128
  • 184
  • 1
    There is a great article about different GUI architectures by Martin Fowler (http://www.martinfowler.com/eaaDev/uiArchs.html). It describes GUI architecture tradeoffs in terms of unit testing. – Roman Hwang Oct 29 '10 at 02:35
  • 1
    Nowadays, this question would be better asked on http://programmers.stackexchange.com (and is probably off-topic on Stack Overflow, on the grounds of being Too Broad), but old questions can't be migrated. The question of whether it belongs here aside, the problem remains an interesting and difficult one. – Mark Amery May 10 '14 at 10:45
  • 1
    It would be great to have example with some GUI piece of code and JUnit. – Witold Kaczurba Oct 27 '16 at 07:01
  • 2
    I would say just relax and don't bother. Effort put into unit tests does not always turn out to be net productive. – codeulike Feb 20 '19 at 11:07
  • Old question still , you can test the flow in the GUI using Jubula – Abi Nov 12 '19 at 06:11

14 Answers14

73

Designs like MVP and MVC typically try to abstract as much logic out of the actual GUI as possible. One very popular article about this is "The Humble Dialog Box" by Michael Feathers. Personally I've had mixed experiences with trying to move logic out of the UI - sometimes it's worked very well, and at other times it's been more trouble than it's worth. It's somewhat outside my area of expertise though.

c24w
  • 7,421
  • 7
  • 39
  • 47
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • ??? "sometimes it's worked very well, and at other times it's been more trouble than it's worth" Very weird because most new language tend to be MVC oriented... which is logic out of the gui (Model-Visual)... – Patrick Desjardins Oct 20 '08 at 15:26
  • 16
    Still, presentation logic will be in the GUI. At times, that may be far from trivial – Andrea Mar 28 '12 at 09:25
  • 17
    Mirror: [The Humble Dialog Box](http://web.archive.org/web/20110721175855/http://www.objectmentor.com/resources/articles/TheHumbleDialogBox.pdf) – c24w Jan 06 '13 at 16:26
  • Martin Fowler's treatment of the concept (in case your network, like mine, filters archive.org): http://www.martinfowler.com/eaaDev/uiArchs.html#HumbleView – Christopher Berman Jul 28 '16 at 14:36
  • _The Humble Dialog Box_ doesn't describe true MVP but rather its early draft, document-view. – ivan_pozdeev Mar 28 '19 at 01:42
42

Of course, the answer is to use MVC and move as much logic out of the GUI as possible.

That being said, I heard from a coworker a long time ago that when SGI was porting OpenGL to new hardware, they had a bunch of unit tests that would draw a set of primatives to the screen then compute an MD5 sum of the frame buffer. This value could then be compared to known good hash values to quickly determine if the API is per pixel accurate.

dicroce
  • 45,396
  • 28
  • 101
  • 140
  • 3
    I like this approach. Cumbersome to set up and maintain, but it would give me the regression testing capabilities I need. – Steve McLeod Oct 19 '08 at 06:22
  • Tried this. Failed miserably. See http://stackoverflow.com/questions/528224/how-to-use-linux-fonts-in-windows-qt – danatel Mar 17 '09 at 07:54
  • 7
    danatel you missed the point. OpenGL is a pixel accurate graphics rendering API. GUI application frameworks like Qt are going to be highly dependent on the system chrome, so hashing the frame buffer is not a good approach. – Bob Somers Jul 01 '09 at 22:59
  • 1
    An MD5? What has a cryptographic hash to do with this? How is security involved? A hash, OK, it's a great idea for pixel-perfect graphics but a cryptographic hash? You can use faster hashes that are non-cryptographic and whose probability of collision is negligible. Are you sure it was a cryptographic hash and not simply a hash? (in addition to that, in this day and age of parallel computing, hashing algorithm [used for non-cryptographic purposes] that cannot be parallelized should be looked upon with suspicion) – SyntaxT3rr0r Jan 25 '10 at 17:44
  • 25
    @SyntaxT3rr0r: What hash function would you recommend in this type of non-security-related application, and what level of performance gain could one expect compared to MD5? – Lèse majesté Jul 04 '12 at 05:33
  • I guess the summary is that there are two ways to test GUIs: (1) write specific use cases that can be manually demonstrated, and (2) get use cases from people complaining about the GUI not behaving correctly. GUIs have an incredible amount of expectations for them and many of them are subjective as well. In conjunction to being highly side-effect driven, and being the most commonly changed part of a system, there is no surprise that they are one of the hardest things to test. It might help to make sure that if a view can't be completely demonstrated in 30 minutes, it should be simplified. – Dmytro Oct 14 '16 at 06:57
  • You guys don't realize how genius this is though... hashing the frame buffer may not be the BEST solution.. however, using the MD5 on the pixel values of the graph image created is a very clever and useful idea. T3rr0r, MD5 hash is used for digest authentication... MD5 is an algorithm where small change creates huge change in the output. You would need screenshots of the correct graph images, and pre-computed hashes of them to make it fast... but thnx dicroce... I have been writing a graphing calc app for some time now and have been fumbling for a good way to test graphs produced... – phriendtj Apr 13 '18 at 14:03
  • @phriendtj, the avalanche effect of cryptographic hashing algorithms is highly pointless in this context. Saying it is important is like saying computers cannot tell the difference between `(2^32) - 1` and `(2^32) - 2`. That is to say, at least based on how I interpret your comment, that you must see an avalanche effect to detect to values as being different. Such should not be the case. Any old hashing algorithm (including non-cryptographic options) should work for this use-case, as the chance of duplicates and resistance to pre-image attacks should be irrelevant. That said, I would use MD5. – Spencer D Feb 24 '19 at 01:49
  • Did a paper on testing OpenGL images a couple of years back. Conclusion: using multiple approximate tests works pretty well for most graphics applications, e.g. testing for big changes in full image luminance, histogram, or even sampling individual pixels. The paper was mostly about computer vision techniques, but in retrospect a lot of issues can be dealt with using several simpler ones. – Andreas Aug 13 '19 at 14:50
10

You can try UISpec4J is an Open Source functional and/or unit testing library for Swing-based Java applications...

Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 2
    I've started using UISpec4J for a month or so for doing requirements validation testing on Java Swing GUI's. I've been liking it a lot so far. – Bassam Jun 16 '09 at 20:44
  • https://github.com/UISpec4J/UISpec4J states that your link is the official website, but it doesn't look that official to me. All I see is a blog about vlogging – lucidbrot Jan 07 '18 at 17:55
  • 1
    @lucidbrot it used to be: http://web.archive.org/web/20090304192541/http://www.uispec4j.org/ – username.ak Nov 20 '21 at 21:54
7

You can try to use Cucumber and Swinger for writing functional acceptance tests in plain english for Swing GUI applications. Swinger uses Netbeans' Jemmy library under the hood to drive the app.

Cucumber allows you to write tests like this:

 Scenario: Dialog manipulation
    Given the frame "SwingSet" is visible
    When I click the menu "File/About"
    Then I should see the dialog "About Swing!"
    When I click the button "OK"
    Then I should not see the dialog "About Swing!"

Take a look at this Swinger video demo to see it in action.

Dema
  • 6,867
  • 11
  • 40
  • 48
7

There is Selenium RC, which will automate testing a web based UI. It will record actions and replay them. You'll still need to walk through the interactions with your UI, so this will not help with coverage, but it can be used for automated builds.

David Robbins
  • 9,996
  • 7
  • 51
  • 82
7

Testing is an art form. I agree the logic should be removed GUI as much as possible. We can then focus our unit testing there. Like anything else testing is about reducing risk. You dont always need to test everything but alot of times the best thing is to break the different testing up for at different areas.

The other question is what are you really trying to test at the UI layer. UI testing is the most expensive testing because it usually takes longer to create, maintain and it is the most brittle. If you test the logic to know the coordinates are correct prior to trying to draw the line what are you testing specifically? If you want to test a graph with a red line is drawn. Can you give it a set predetermined coordinates and test if certain pixels are red or not red? As suggested above bitmap comparisons work, Selenium but my main focus would be not to over test the GUI but rather test the logic that will help create the UI and then focus on what portion of the UI breaks or is suspect and focus a handful of tests there.

Charles Smith
  • 71
  • 1
  • 1
6

Here is some tips:

Try to remove the most code you can from the GUI (have controller, and model object) this way you will be able to test them without the GUI.

For the graphic, you should test the value that you supply to the code that generate the graphic.

Patrick Desjardins
  • 136,852
  • 88
  • 292
  • 341
3

You can use JFCUnit to test your GUI, but graphics can be more challenging. I have on a couple of occasions taken snapshots of my GUI and automatically compared it to a previous version. While this doesn't provide an actual test, it does alert you if an automatic build fails to produce the expected output.

Steve Moyer
  • 5,663
  • 1
  • 24
  • 34
3

What I gather from your question is that you're looking for an automated way to test your GUI behavior in detail, the example you give is testing whether a curve is actually drawn correctly.

Unit testing frameworks provide a way to do automated testing, but I think the kind of tests you want to do are complicated integration tests that verify the correct behavior of a multitude of classes, among which the classes of your GUI toolkit/library, which you should not want to test.

Your options depend very much on what platforms/toolkits/frameworks you use: for example, an application using Qt as its GUI framework can use Squish to automate its tests. You verify the results of your tests once, and subsequent automatically executed tests compare results against the verified results.

andreas buykx
  • 12,608
  • 10
  • 62
  • 76
3

My approach to GUI testing is evolving, as is the industry consensus. But I think a few key techniques are beginning to emerge.

I use one or more of these techniques, depending on the situation (e.g. what kind of GUI it is, how quickly it needs to be built, who the end-user will be, etc.).

  1. Manual testing. You always have the GUI running while working on the code, and ensure it is in sync with the code. You manually test and re-test the part that you work on as you work on it, switching between the code and the running application. Every time you complete some significant piece of work, you give the whole screen or area of the application an overall test, to ensure there are no regressions.

  2. Unit testing. You write tests for functions or small units of GUI behaviour. For example, your graphs may need to calculate different shades of a colour based on a 'base' colour. You can extract this calculation to a function and write a unit test for it. You can search for logic like this in the GUI (especially re-usable logic) and extract it into discreet functions, which can be more easily unit tested. Even complex behaviour can be extracted and tested in this manner – for example, a sequence of steps in a wizard can be extracted to a function and a unit-test can verify that, given an input, the correct step is returned.

  3. Component explorer. You create an 'explorer' screen whose only role is to showcase each of the re-usable components that make up your GUI. This screen gives you a quick and easy way to visually verify that every component has the correct look & feel. The component explorer is more efficient than manually going through your whole application, because A) you only have to verify each component once, and B) you don't have to navigate deep into the application to see the component, you can just view and verify it immediately.

  4. Automation testing. You write a test that interacts with the screen or component, simulating mouse clicks, data entry, etc., asserting that the application functions correctly given these manipulations. This can be useful as an extra backup test, to capture potential bugs that your other tests might miss. I tend to reserve automation testing for the parts of the GUI that are most prone to breaking and/or are highly critical. Parts where I want to know as early as possible if something has broken. This could include highly complex interactive components that are vulnerable to breaking or important main screens.

  5. Diff/snapshot testing. You write a test that simply captures the output as a screenshot or as HTML code and compares it with the previous output. That way, you're alerted you whenever the output changes. Diff tests may be useful if the visual aspect of your GUI is complex and/or subject to change, in which case, you want quick and visual feedback on what impact a given change has on the GUI as a whole.

Rather than heavy-handedly using every possible kind of test, I prefer to pick and choose the testing technique based on the kind of thing I'm working on. So in one case I'll extract a simple function and unit-test it, but in another case I'll add a component to the component explorer, etc. It depends on the situation.

I haven't found code coverage to be a very useful metric, but others may have found a use for it.

I think the first measure is the number and severity of bugs. Your first priority is probably to have an application that functions correctly. If the application functions correctly, there should few or no bugs. If there are many or severe bugs, then presumably, you are either not testing or your tests are not effective.

Other than reducing bugs, there are other measures such as performance, usability, accessibility, maintainability, extensibility, etc. These will differ, depending on what kind of application you're building, the business, the end-user, etc.

This is all based on my personal experience and research as well as a great write-up on UI Tests by Ham Vocke.

Jonathan
  • 32,202
  • 38
  • 137
  • 208
2

Window Licker for Swing & Ajax

robi-y
  • 1,687
  • 16
  • 25
1

From what I know, this is quite complicated, and really depends on the language - numerous languages have their own way of testing GUI, but if you really need to test the GUI (as opposed to model/gui interaction), you often have to simulate an actual user clicking buttons. For example, the SWT framework used in Eclipse provides SWTBot, JFCUnit has already been mentioned, Mozilla has their own way of simulating this in XUL (and from what I've read on their blogs, these tests seem to be quite brittle).

Sometimes you have to take a screenshot, and test for pixel-perfect rendering (I believe that Mozilla does this to check for correctly rendered pages) - this requires a lengthier setup, but might be what you need for the graphs. That way, when you update your code and a test breaks, you have to manually check the image if the failure was real, or you improved the graph rendering code to generate prettier graphs and need to update the screenshots.

Kim Sullivan
  • 943
  • 2
  • 10
  • 15
0

If you are using Swing, FEST-Swing is useful for driving your GUI and testing assertions. It makes it pretty straightforward to test things like "if I click button A, dialog B should be displayed" or "if I select option 2 from the drop-down, all the checkboxes should become deselected".

The graph scenario that you mention is not so easy to test. It's pretty easy to get code coverage for GUI components just by creating and displaying them (and perhaps driving them with FEST). However, making meaningful assertions is the hard part (and code coverage without meaningful assertions is an exercise in self-deception). How do you test that the graph was not drawn upside-down, or too small?

I think that you just have to accept that some aspects of GUIs cannot be tested effectively by automated unit tests and that you will have to test them in other ways.

Dan Dyer
  • 53,737
  • 19
  • 129
  • 165
0

It's not your job to test the GUI library. So you can dodge the responsibility to check what is actually drawn on screen and check widgets' properties instead, trusting the library that they accurately represent what is drawn.

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152