{"id":1232,"date":"2014-09-25T10:10:16","date_gmt":"2014-09-25T17:10:16","guid":{"rendered":"http:\/\/10kdev.net\/?p=1232"},"modified":"2014-09-25T10:10:56","modified_gmt":"2014-09-25T17:10:56","slug":"joptionpane-popping-up-during-unit-tests","status":"publish","type":"post","link":"http:\/\/10kdev.net\/?p=1232","title":{"rendered":"JOptionPane Popping Up During Unit Tests"},"content":{"rendered":"<p>This story is the story of good old fashioned decoupling, and an example of Java&#8217;s <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bridge_pattern\">Bridge<\/a> and <a href=\"https:\/\/en.wikipedia.org\/wiki\/Adapter_pattern#Class_Adapter_pattern\">Adapter<\/a> patterns.<\/p>\n<p>My client has had a piece of code that for years, yes years, was popping up a java Swing <a href=\"http:\/\/docs.oracle.com\/javase\/7\/docs\/api\/javax\/swing\/JOptionPane.html\">JOptionPane<\/a> message dialog during unit tests runs in Eclipse (via a Maven plugin) and Eclipse&#8217;s JUnit runner. \u00a0The surprising thing is that all the developers would tolerate this . . . and all the developers would run their builds inside of Eclipse.<\/p>\n<p>The codebase sits on SVN, and I&#8217;ve been running git-svn infront of it and using the command line quite a bit. \u00a0My builds have all been terminal-based Maven or a build script also run from the terminal. For whatever reason I couldn&#8217;t pin down &#8212; maybe a global suppress warnings &#8212; I wasn&#8217;t getting the dialogs. \u00a0But I *was* aware of the problem because I make sure my stuff runs in Eclipse as well. So I logged it in my Kanboard database and came back to it.<\/p>\n<p>The solution was a bit simple, just bury JOptionPane in another interface layer. \u00a0 I had thought about it, then researched soloutions regarding Swing component testing (seriously how many fat clients do we Java people write these days?). \u00a0Lot&#8217;s of static methods and I haven&#8217;t finished dropping in PowerMock and its module for\u00a0Mockito yet. I followed\u00a0the bridge\/adapter path written up by <a href=\"http:\/\/shervinasgari.blogspot.com\/2012\/07\/unit-testing-with-joptionpane.html\">Shervin Asgari<\/a> and thank him. \u00a0The technique is fundamental enough, and overlooked enough, that I feel compelled to write it up here.<\/p>\n<p>Inside some of our service code is this pop-up for an error:<\/p>\n<pre><code>\r\n\/\/Service code\r\npublic void codeMethod() {\r\n   try {\r\n      \/\/...something and maybe error\r\n   } catch (Exception e) {\r\n      LOG.error(\"Service exception: \" + e.getMessage(), e);\r\n      JOptionPane.showMessageDialog(null, \"Service is broken.  Contact help support\", \"\", \r\n      JOptionPane.ERROR_MESSAGE);\r\n   }\r\n)<\/code><\/pre>\n<p>Again the problem is, when running JUnit tests via Maven *in* Eclipse or via the Junit runner, the pop-up shows and requires response. We don&#8217;t want this for obvious reasons.<\/p>\n<p>Unfortunately this Swing widget has a lot of static methods so we can&#8217;t simply extend the class with an interface and mock that interface. The solution instead is to make an separate interface and implementation, calling the JOptionPane methods.<\/p>\n<p>First I make an interface and a concrete implementation, the latter which executes the JOptionPane method:<\/p>\n<pre><code>\r\npublic interface OptionPane {\r\n   public void showMessageDialog(Component parentComponent, Object message, \r\n   String title, int messageType);\r\n}\r\n\r\npublic class OptionPaneImpl implements OptionPane {\r\n   public OptionPaneImpl() {\r\n      \/\/intentional\r\n   }\r\n   \/*** we have moved the code from the service to here ***\/\r\n   public void showMessageDialog(Component parentComponent, Object message, \r\n   String title, int messageType) {\r\n      JOptionPane.showMessageDialog(parentComponent,message,title,messageType);\r\n   }\r\n}\r\n<\/code><\/pre>\n<p>Now we put\u00a0the code into the service, and we are ready for mock testing:<\/p>\n<pre><code>\/\/Service code\r\nprivate OptionPane optionPane = new OptionPaneImpl();<\/code><\/pre>\n<pre><code>\r\npublic void codeMethod() {\r\n   try {\r\n      \/\/...something and maybe error\r\n   } catch (Exception e) {\r\n      LOG.error(\"Service exception: \" + e.getMessage(), e);\r\n      optionPane.showMessageDialog(null, \"Service is broken.  Contact help support\", \"\", \r\n      JOptionPane.ERROR_MESSAGE); \/\/&lt;-- swapped the interface into here\r\n   }\r\n)\r\n<\/code><\/pre>\n<p>Here&#8217;s what the test looks like with JUnit\/Mockito:<\/p>\n<pre><code>\r\npublic class ServiceCodeTest\r\n{\r\n   @InjectMocks\r\n   private ServiceCode serviceCode;\r\n\r\n   @Mock\r\n   private OptionPane mockOptionPane;\r\n\r\n   @Before\r\n   public void setUp() {\r\n      MockitoAnnotations.initMocks(this);\r\n   }\r\n\r\n   @Test\r\n   public void testDoCalculate() throws Exception\r\n  {\r\n     \/\/comment out mock declaration and following stub to see message dialog\r\n     doNothing().when(mockOptionPane).showMessageDialog(any(Component.class), \r\n     anyObject(), anyString(), anyInt());\r\n\r\n     serviceCode.doCodeMethod();\r\n  }\r\n}\r\n<\/code><\/pre>\n<p>There almost never seems to be a reason *not* to use an interface.  At worse you just write a few extra lines of code but the decoupling, extendability and testability are invaluable. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>This story is the story of good old fashioned decoupling, and an example of Java&#8217;s Bridge and Adapter patterns. My client has had a piece of code that for years, yes years, was popping up a java Swing JOptionPane message dialog during unit tests runs in Eclipse (via a Maven plugin) and Eclipse&#8217;s JUnit runner. [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[55,54,29,57,53,58,56],"_links":{"self":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts\/1232"}],"collection":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1232"}],"version-history":[{"count":10,"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts\/1232\/revisions"}],"predecessor-version":[{"id":1252,"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts\/1232\/revisions\/1252"}],"wp:attachment":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1232"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1232"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1232"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}