{"id":2177,"date":"2013-11-22T08:38:25","date_gmt":"2013-11-21T20:38:25","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2177"},"modified":"2013-11-22T09:01:04","modified_gmt":"2013-11-21T21:01:04","slug":"interfaces-vs-inheritance","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2177\/","title":{"rendered":"Smoketest &#8211; Interfaces vs Inheritance"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>A couple of commenters on my previous post have taken issue with my use of interfaces to form contracts between test cases and the test framework, rather than using simple virtual methods and inheritance as found in <strong>DUnit<\/strong>.  I thought it would be interesting to illustrate why I went down this route.<\/p>\n<p><!--more--><\/p>\n<p>It is suggested that using inheritance means that discovering the methods required to be implemented to support <strong>Setup<\/strong>\/<strong>TearDown<\/strong> in <strong>DUnit<\/strong> is simpler than having to know the required interface name and then having to lookup the method signature involved, as in the case of <strong>Smoketest<\/strong>.<\/p>\n<p>This of course assumes that documentation either does not exist or is being wilfully ignored.<\/p>\n<p>First of all, the interfaces in <strong>Smoketest<\/strong> are designed to be highly memorable.  They read as a natural description of a behaviour that a test case class follows.<\/p>\n<p>Where a test case has some project setup to perform it states &#8220;<em>I Setup (the) Project<\/em>&#8220;.  If it has some setup to perform specific to the test case &#8220;<em>I Setup (this) Test Case<\/em>&#8220;.  And so on.<\/p>\n<p>So remembering the interface name really shouldn&#8217;t be hard, since it describes what you wish to achieve.  Whether you intuit the interface name, select it from the fairly short list of interfaces offered by IDE Code Completion, the chances are you will only have to look it up once.<\/p>\n<p>The compiler then ensures that the contract is fulfilled.<\/p>\n<p>So let&#8217;s assume you at least know the interface involved and look at the impact that using the interface has on finding the method(s) required, as compared to finding the method from the list of inherited methods.<\/p>\n<p>First, let&#8217;s look at what the IDE offers when we invoke <strong>Code Completion<\/strong> in the class declaration of a <strong>DUnit<\/strong> test case.<\/p>\n<figure id=\"attachment_2178\" aria-describedby=\"caption-attachment-2178\" style=\"width: 382px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.02.08.png?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.02.08.png?resize=382%2C607&#038;ssl=1\" alt=\"Page 1 of 3\" width=\"382\" height=\"607\" class=\"size-full wp-image-2178\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.02.08.png?w=382&amp;ssl=1 382w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.02.08.png?resize=188%2C300&amp;ssl=1 188w\" sizes=\"auto, (max-width: 382px) 100vw, 382px\" \/><\/a><figcaption id=\"caption-attachment-2178\" class=\"wp-caption-text\">Page 1 of 3<\/figcaption><\/figure>\n<p>I made my suggestion list popup as big as I possibly could, but they aren&#8217;t on even the first page of this greatly enlarged list so scrolling down to the next complete page of suggestions &#8230;.<\/p>\n<figure id=\"attachment_2179\" aria-describedby=\"caption-attachment-2179\" style=\"width: 382px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.02.29.png?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.02.29.png?resize=382%2C602&#038;ssl=1\" alt=\"Page 2 of 3\" width=\"382\" height=\"602\" class=\"size-full wp-image-2179\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.02.29.png?w=382&amp;ssl=1 382w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.02.29.png?resize=190%2C300&amp;ssl=1 190w\" sizes=\"auto, (max-width: 382px) 100vw, 382px\" \/><\/a><figcaption id=\"caption-attachment-2179\" class=\"wp-caption-text\">Page 2 of 3<\/figcaption><\/figure>\n<p>Aha &#8211; there they are.  <strong>Setup<\/strong> and <strong>Teardown<\/strong>.  Look carefully, you will see them eventually.<\/p>\n<p>Of course, to find them you have to already know what you are looking for since they are simply listed alphabetically among all the other methods that you have no intention of implementing yourself.<\/p>\n<p>I don&#8217;t see any methods for performing per-test or project-wide setup\/teardown though, so I am not entirely sure of the context in which <strong>Setup<\/strong> and <strong>Teardown<\/strong> operate.  I guess I&#8217;ll have to read the documentation after all.  \ud83d\ude42<\/p>\n<p>Now let&#8217;s look at the same <strong>Code Completion<\/strong> offering for a <strong>Smoketest<\/strong> test case class declaration:<\/p>\n<figure id=\"attachment_2180\" aria-describedby=\"caption-attachment-2180\" style=\"width: 362px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.04.18.png?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.04.18.png?resize=362%2C101&#038;ssl=1\" alt=\"TOP OF THE BILL!\" width=\"362\" height=\"101\" class=\"size-full wp-image-2180\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.04.18.png?w=362&amp;ssl=1 362w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-22-at-09.04.18.png?resize=300%2C83&amp;ssl=1 300w\" sizes=\"auto, (max-width: 362px) 100vw, 362px\" \/><\/a><figcaption id=\"caption-attachment-2180\" class=\"wp-caption-text\">TOP OF THE BILL!<\/figcaption><\/figure>\n<p>Well, would you look at that.  The methods introduced by my specified interface contracts (in this case, that I will provide a name for the case and that I perform some test case setup), are put front and centre.<\/p>\n<p>Now, without the interfaces declared on the class, I would see no such methods at all.  But is this really a problem ?  I don&#8217;t think so.  The list of available methods is itself much shorter and the complete lack of any setup\/cleanup methods will itself remind me that I have to form my contract with the framework first.<\/p>\n<p>And I then get to choose <strong>which<\/strong> contract &#8211; setting up specific test methods, the test case or project wide setup (and\/or attendant cleanup).<\/p>\n<p>On that note, issue has also been taken with the use of &#8220;<em>Cleanup<\/em>&#8221; rather than &#8220;<em>TearDown<\/em>&#8221; in the method and interface names.  This was deliberate.  <strong>TearDown<\/strong> has a finality about it that seemed to be most often not appropriate.<\/p>\n<p>Take for example the JSON test case which performs some cleanup after every test method by clearing a JSON object in preparation for the next test method.  This really isn&#8217;t &#8220;tearing anything down&#8221;.  It really <strong>is<\/strong> just &#8220;cleaning up&#8221;.<\/p>\n<p>Sometimes your cleanup <em>will<\/em> involve completely destroying some artefacts used\/created during testing, but this is just one extreme form of cleanup.<\/p>\n<p>When the house-work needs doing, do you tear down your house or do you clean it up ?<\/p>\n<p>Even tearing down the house, if\/when it ever becomes necessary, is only what you do in order to &#8220;clean&#8221; the site, in readiness for a new house to be built.<\/p>\n<p><strong>TearDown<\/strong> may appeal to some people&#8217;s sense of the dramatic, but other than that it is actually a very poor choice of name imho.<\/p>\n<p>I didn&#8217;t create <strong>Smoketest<\/strong> in order to simply create a plug-compatible alternative to <strong>DUnit<\/strong>.  I didn&#8217;t even create it as a &#8220;competitor&#8221; for <strong>DUnit<\/strong>.  I created it for myself precisely because I didn&#8217;t and don&#8217;t like the way <strong>DUnit<\/strong> works.<\/p>\n<p>And because <strong>DUnit<\/strong> didn&#8217;t and doesn&#8217;t do some things that I wanted and needed (see my next post).<\/p>\n<p>I simply choose now to share it.<\/p>\n<p>If you do like the way <strong>DUnit<\/strong> works you are of course more than welcome to continue using it, but don&#8217;t expect <strong>Smoketest<\/strong> to conform to any expectations you might bring from that other framework.  \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>A couple of commenters on my previous post have taken issue with my use of interfaces to form contracts between test cases and the test framework, rather than using simple virtual methods and inheritance as found in DUnit. I thought it would be interesting to illustrate why I went down this route.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[4],"tags":[261,51],"class_list":["post-2177","post","type-post","status-publish","format-standard","hentry","category-delphi","tag-deltics","tag-smoketest"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-z7","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2177","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=2177"}],"version-history":[{"count":5,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2177\/revisions"}],"predecessor-version":[{"id":2189,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2177\/revisions\/2189"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2177"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2177"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2177"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}