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
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
<h1>Groovy Mocks</h1> <p>Groovy has excellent built-in support for a range of mocking alternatives. Before considering those, let's review some relevant terms.</p> <h2>Terms</h2> <h3>Collaborator</h3> <p>An ordinary Groovy or Java class that's instance or class methods are to be called.<br /> Calling them can be time consuming or produce side effects that are unwanted when testing (e.g. database operations).</p> <h3>Caller</h3> <p>A Groovy Object that calls methods on the Collaborator, i.e. collaborates with it.</p> <h3>Mock</h3> <p>An object that can be used to augment the Collaborator. Method calls to the Collaborator will be handled by the Mock, showing a <em>demanded</em> behavior. Method calls are <em>expected</em> to occur <em>strictly</em> in the <em>demanded</em> sequence with a given <em>range</em> of cardinality. The use of a Mock implicitly ends with <em>verifying</em> the expectations.</p> <h3>Stub</h3> <p>Much like a Mock but the <em>expectation</em> about sequences of method calls on the Collaborator is <em>loose</em>, i.e. calls may occur <span style="text-decoration: underline;">out of</span> the <em>demanded</em> order as long as the <em>ranges</em> of cardinality are met. The use of a Stub does <span style="text-decoration: underline;">not</span> end with an implicit verification since the stubbing effect is typically asserted on the Caller. An <span style="text-decoration: underline;">explicit</span> call to <em>verify</em> can be issued to assert all <em>demanded</em> method calls have been effected with the specified cardinality.</p> <h2>An extended example</h2> <h3>System under test</h3> <p>We will explore a system under test inspired from the <a href="http://jbehave.org/">JBehave</a> currency example.</p> <p>Our system makes use of a base currency class used to represent the currency of a particular country:</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 Currency { public static final Currency USD = new Currency("USD") public static final Currency EUR = new Currency("EUR") private String currencyCode private Currency(String currencyCode) { this.currencyCode = currencyCode } public String toString() { return currencyCode } } </pre></td></tr></table> <p>and a base exchange rate class which encapsulates buying and selling rates for a currency:</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 ExchangeRate { final double fromRate final double toRate public ExchangeRate(double fromRate, double toRate) { this.fromRate = fromRate this.toRate = toRate } } </pre></td></tr></table> <p>We will make use of an exchange rate service collaborator to retrieve the exchange rates for a particular country:</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 ExchangeRateService { ExchangeRate retrieveRate(Currency c) } </pre></td></tr></table> <p>Our class under test is a currency converter. It makes use of the following exception:</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 InvalidAmountException extends Exception { public InvalidAmountException(String message) {super(message);} } </pre></td></tr></table> <p>and conforms to the following interface:</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 CurrencyConverter { double convertFromSterling(double amount, Currency toCurrency) throws InvalidAmountException double convertToSterling(double amount, Currency fromCurrency) throws InvalidAmountException } </pre></td></tr></table> <p>Here is our class under test.</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 SterlingCurrencyConverter implements CurrencyConverter { private ExchangeRateService exchangeRateService public SterlingCurrencyConverter(ExchangeRateService exchangeRateService) { this.exchangeRateService = exchangeRateService; } private double convert(double amount, double rate) throws InvalidAmountException { if (amount < 0) { throw new InvalidAmountException("amount must be non-negative") } return amount * rate } public double convertFromSterling(double amount, finance.Currency toCurrency) throws InvalidAmountException { return convert(amount, exchangeRateService.retrieveRate(toCurrency).fromRate) } public double convertToSterling(double amount, finance.Currency fromCurrency) throws InvalidAmountException { return convert(amount, exchangeRateService.retrieveRate(fromCurrency).toRate) } } </pre></td></tr></table> <h3>Mocking using Map coercion</h3> <p>When using Java, Dynamic mocking frameworks are very popular. A key reason for this is that it is hard work creating custom hand-crafted mocks using Java. Such frameworks can be used easily with Groovy if you choose (as shown in this <a class="confluence-link" href="/display/GROOVY/Using+Other+Testing+Frameworks" data-linked-resource-id="12681270" data-linked-resource-type="page" data-linked-resource-default-alias="Using Other Testing Frameworks" data-base-url="http://docs.codehaus.org">extended example</a>) but creating custom mocks is much easier in Groovy. You can often get away with simple maps or closures to build your custom mocks.</p> <p>Let's consider maps first.</p> <p>By using maps or expandos, we can incorporate desired behaviour of a collaborator very easily as shown here:</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 service = [retrieveRate:{ new ExchangeRate(1.45, 0.57) }] as ExchangeRateService def sterlingConverter = new SterlingCurrencyConverter(service) double convertedAmount = sterlingConverter.convertFromSterling(10.0, Currency.USD); assert convertedAmount == 14.50 </pre></td></tr></table> <p>For more details, see <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>.</p> <h3>Mocking using Closure coercion</h3> <p>Alternatively, we can use closures:</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> service = { new ExchangeRate(1.55, 0.56) } as ExchangeRateService sterlingConverter = new SterlingCurrencyConverter(service) convertedAmount = sterlingConverter.convertFromSterling(10.0, Currency.USD); assert convertedAmount == 15.50 </pre></td></tr></table> <p>For more details, see <a class="confluence-link" href="/display/GROOVY/Developer+Testing+using+Closures+instead+of+Mocks" data-linked-resource-id="66905" data-linked-resource-type="page" data-linked-resource-default-alias="Developer Testing using Closures instead of Mocks" data-base-url="http://docs.codehaus.org">Developer Testing using Closures instead of Mocks</a>.</p> <h3>Mocking using MockFor and StubFor</h3> <p>If we need the full power of a dynamic mocking framework, Groovy has a built-in framework which makes use of meta-programming to define the behaviour of the collaborator. An example is shown here:</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> import groovy.mock.interceptor.* def mockContextClass = new MockFor(DummyExchangeRateService) mockContextClass.demand.retrieveRate { new ExchangeRate(1.65, 0.55) } class DummyExchangeRateService implements ExchangeRateService { ExchangeRate retrieveRate(Currency currency){} } mockContextClass.use { def dummyService = new DummyExchangeRateService() sterlingConverter = new SterlingCurrencyConverter(dummyService) convertedAmount = sterlingConverter.convertFromSterling(10.0, Currency.USD) assert convertedAmount == 16.50 } </pre></td></tr></table> <p>This approach works well for testing Groovy classes. In the current versions of Groovy (Groovy 1.5 and 1.6 beta1 at the time of writing this page), the behavior that you define with <code>demand</code> clauses represents the behavior of all of the instances of the mocked class type. For more details, see <a class="confluence-link" href="/display/GROOVY/Using+MockFor+and+StubFor" data-linked-resource-id="30015499" data-linked-resource-type="page" data-linked-resource-default-alias="Using MockFor and StubFor" data-base-url="http://docs.codehaus.org">Using MockFor and StubFor</a>.</p> <h3>Instance-style MockFor and StubFor</h3> <p>You can also use MockFor and StubFor in a more traditional style by creating instances 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> mockContext1 = new MockFor(ExchangeRateService) mockContext1.demand.retrieveRate { new ExchangeRate(1.75, 0.54) } def dummyService1 = mockContext1.proxyInstance() def sterlingConverter1 = new SterlingCurrencyConverter(dummyService1) convertedAmount1 = sterlingConverter1.convertFromSterling(10.0, Currency.USD) mockContext1.verify dummyService1 assert convertedAmount1 == 17.50 mockContext2 = new MockFor(ExchangeRateService) mockContext2.demand.retrieveRate(1){ new ExchangeRate(1.85, 0.53) } def dummyService2 = mockContext2.proxyInstance() def sterlingConverter2 = new SterlingCurrencyConverter(dummyService2) convertedAmount2 = sterlingConverter2.convertFromSterling(10.0, Currency.USD) mockContext2.verify dummyService2 assert convertedAmount2 == 18.50 </pre></td></tr></table> <p>This approach let's you have multiple instances of the same class all with different behaviors. Also, note that you have to explicitly call the <code>verify</code> method here if you want to check that the <em>demanded</em> behavior was in fact observed. Also, you can use this technique for testing Java classes but you need to call <code>proxyDelegateInstance()</code> instead of <code>proxyInstance()</code>.</p>
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