This blog is mainly about Java...

Thursday, July 19, 2012

Unit testing with JOptionPane

If you are like me, you would still like to be able to unit test your swing applications.

However, its difficult to do this when you have a JOptionPane.showConfirmationDialog, and the user needs to type in yes or no.

In this blog post I will show you how you can accomplish this without needing the user to add anything, or changing your domain code too much.


Lets say you have a simple JFrame you want to test that contains a JOptionPane.


public class SimpleFrame extends JFrame {

  public boolean simpleMethod() {
    int showConfirmDialog = JOptionPane.showConfirmDialog(this, "Can we write test for this?", "Question", JOptionPane.YES_NO_OPTION);
    return showConfirmDialog == JOptionPane.YES_OPTION;
  }
}


Now if you create a JUnit test for this, and run it, you will get a JOptionPane and you need to press the YES or NO button.

To avoid this we can change the code to use an interface and then we can create a mock OptionPane for you tests.



/*
* Note you can add all the methods you use in your application
*/
public interface OptionPane {

      /**
       *  @see JOptionPane#showConfirmDialog(Component, Object, String, int, int);
       */
      int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType);
}


Create three implementations of this interface. One that is delegating to JOptionPane, and the others that will be our mock. One of the mocks will return yes, the other no.


public class DefaultOptionPane implements OptionPane {

      public int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) {
         return JOptionPane.showConfirmDialog(parentComponent,message,title,optionType,messageType);
      }
}

public class YesMockOptionPane extends MockOptionPane {

        @Override
 public int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) {
   return JOptionPane.YES_OPTION;
 }
}


public class NoMockOptionPane extends MockOptionPane {

        @Override
 public int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) {
   return JOptionPane.NO_OPTION;
 }
}



Now change your application and add the OptionPane


public class SimpleFrame extends JFrame {
  private OptionPane optionPane = DefaultOptionPane();
  
  public boolean simpleMethod() {
    int showConfirmDialog = optionPane.showConfirmDialog(this, "Can we write test for this?", "Question", JOptionPane.YES_NO_OPTION);
    return showConfirmDialog == JOptionPane.YES_OPTION;
  }

  public void setOptionPane(OptionPane o) { this.optionPane = o; }
}


Now in your tests you use the appropriate MockOptionPane.



@Test
public void test() throws Exception {
  SimpleFrame s = new SimpleFrame()
  s.setOptionPane(new YesMockOptionPane());
  Assert.assertTrue(s.simpleMethod());
}

No comments:

Labels