Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Sign Up
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<p>Groovy's 'as' operator can be used with closures in a neat way which is great for developer testing in simple scenarios. We haven't found this technique to be so powerful that we want to do away with dynamic mocking, but it can be very useful in simple cases none-the-less.</p> <p>Suppose we are using <a href="http://www.pragmaticprogrammer.com/titles/kpiod/index.html">Interface Oriented Design</a> and as sometimes advocated we have defined a number of short interfaces as per below. (Note: we ignore the discussion about whether interfaces are as valuable a design approach when using dynamic languages that support duck-typing.)</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> interface Logger { def log(message) } interface Helper { def doSomething(param) } interface Factory { Helper getInstance() } </pre></td></tr></table> <p>Now, using a coding style typically used with <a href="http://www.martinfowler.com/articles/injection.html">dependency injection</a> (as you might use with <a href="http://www.springframework.org/">Spring</a>), we might code up an application class as follows:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class MyApp { private factory private logger MyApp(Factory factory, Logger logger) { this.logger = logger this.factory = factory } def doMyLogic(param) { factory.getInstance().doSomething(param) logger.log('Something done with: ' + param) } } </pre></td></tr></table> <p>To testing this, we could use <a href="http://groovy.codehaus.org/Groovy+Mocks">Groovy's built-in mocking</a> or some other Java-based dynamic mocking framework. Alternatively, we could write our own static mocks. But no one does that these days I hear you say! Well, they never had the ease of using closures, which bring dynamic power to static mocks, so here we go:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def param = 'DUMMY STRING' def logger = { message -> assert message == 'Something done with: ' + param} def helper = { assert it == param } def factory = { helper as Helper } def myApp = new MyApp(factory as Factory, logger as Logger) myApp.doMyLogic(param) </pre></td></tr></table> <p>That was easy. Behind the scenes, Groovy creates a proxy object for us that implements the interface and is backed by the closure.</p> <p>Easy yes, however, the technique as described above assumes our interfaces all have one method. What about more complex examples? Well, the 'as' method works with Maps of closures too. Suppose our helper interface was defined as follows:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> interface Helper { def doSomething(param) def doSomethingElse(param) } </pre></td></tr></table> <p>And our application modified to use both methods:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> ... def doMyLogic(param) { def helper = factory.getInstance() helper.doSomething(param) helper.doSomethingElse(param) logger.log('Something done with: ' + param) } ... </pre></td></tr></table> <p>We simply use a map of closures with the key used being the same name as the methods of the interface, like so:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> ... def helperMethod = { assert it == param } def helper = [doSomething:helperMethod, doSomethingElse:helperMethod] // as before def factory = { helper as Helper } ... </pre></td></tr></table> <p>Still easy!</p> <p>For this simple example, where we wanted each method to be the same (i.e. implementing the same code) we could have done away with the map altogether, e.g. the following would work, making each method be backed by the closure:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def factory = { helperMethod as Helper } </pre></td></tr></table> <h2>More Information</h2> <p>See also:</p> <ul> <li><a class="confluence-link" href="/display/GROOVY/Developer+Testing+using+Maps+and+Expandos+instead+of+Mocks" data-linked-resource-id="68531" data-linked-resource-type="page" data-linked-resource-default-alias="Developer Testing using Maps and Expandos instead of Mocks" data-base-url="http://docs.codehaus.org">Developer Testing using Maps and Expandos instead of Mocks</a></li> <li><a class="confluence-link" href="/display/GROOVY/Groovy+way+to+implement+interfaces" data-linked-resource-id="69781" data-linked-resource-type="page" data-linked-resource-default-alias="Groovy way to implement interfaces" data-base-url="http://docs.codehaus.org">Groovy way to implement interfaces</a></li> </ul>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced