groovy

Support Half-Mocks

Details

  • Type: New Feature New Feature
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: 1.0
  • Fix Version/s: 1.7.1
  • Component/s: mocks and stubs
  • Labels:
    None
  • Testcase included:
    yes
  • Patch Submitted:
    Yes
  • Number of attachments :
    2

Description

Half-Mocks are mocks for classes with dynamic methods or properties. One example are Grails domain objects where you would use the implemented domain specific methods but want to mock the GORM methods.

Issue Links

Activity

Hide
Paul King added a comment -

OK, I now have a patch (borrowing from Stefan's patch and also the recent ignore amendments) which supports a form of half-mocks. It needs further testing and doco before committing to trunk but to give a flavor:

import groovy.mock.interceptor.MockFor
class Person {
  String first, last
  def name() { "$first $last" }
  def ignoreMe() { 'baz' }
  def ignoreMeToo() { ignoreMe() }
  def ignoreMeThree() { ignoreMe() }
}
def mock = new MockFor(Person)
mock.ignore(~'get.*')
mock.ignore('ignoreMeToo') { 'boo' }
mock.ignore(~'ignoreMe.*')
mock.demand.name{ 'John' }
mock.use {
  def p = new Person(first:'Mary', last:'Smith')
  assert p.first == 'Mary'
  assert p.last == 'Smith'
  assert p.name() == 'John'
  assert p.ignoreMe() == 'baz'
  assert p.ignoreMeToo() == 'boo'
  assert p.ignoreMeThree() == 'baz'
}

Basically, all method calls must match according to the appropriate expectation unless explicitly ignored. When ignoring, a closure can be provided to return a value (much like a demand return result) but the call won't be included when comparing with expected calls. If the ignore method has no return closure, then it defaults through to calling the original underlying instance.

Show
Paul King added a comment - OK, I now have a patch (borrowing from Stefan's patch and also the recent ignore amendments) which supports a form of half-mocks. It needs further testing and doco before committing to trunk but to give a flavor:
import groovy.mock.interceptor.MockFor
class Person {
  String first, last
  def name() { "$first $last" }
  def ignoreMe() { 'baz' }
  def ignoreMeToo() { ignoreMe() }
  def ignoreMeThree() { ignoreMe() }
}
def mock = new MockFor(Person)
mock.ignore(~'get.*')
mock.ignore('ignoreMeToo') { 'boo' }
mock.ignore(~'ignoreMe.*')
mock.demand.name{ 'John' }
mock.use {
  def p = new Person(first:'Mary', last:'Smith')
  assert p.first == 'Mary'
  assert p.last == 'Smith'
  assert p.name() == 'John'
  assert p.ignoreMe() == 'baz'
  assert p.ignoreMeToo() == 'boo'
  assert p.ignoreMeThree() == 'baz'
}
Basically, all method calls must match according to the appropriate expectation unless explicitly ignored. When ignoring, a closure can be provided to return a value (much like a demand return result) but the call won't be included when comparing with expected calls. If the ignore method has no return closure, then it defaults through to calling the original underlying instance.
Hide
Paul King added a comment -

Proposed patch (sans complete tests) attached. Sorry for noise as GROOVY-1823 is merged in this patch. Note that the relaying from an ignored method to a non-existing demanded method is not supported as it was in Stefan's patch. I am currently regarding that as an anti-feature but am open to being persuaded that is not the case.

Show
Paul King added a comment - Proposed patch (sans complete tests) attached. Sorry for noise as GROOVY-1823 is merged in this patch. Note that the relaying from an ignored method to a non-existing demanded method is not supported as it was in Stefan's patch. I am currently regarding that as an anti-feature but am open to being persuaded that is not the case.
Hide
Paul King added a comment -

Added in trunk

Show
Paul King added a comment - Added in trunk

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: