MockFor (groovy 2.4.15 API)
Date: 2018-03-23

Package: groovy.mock.interceptor

## [Groovy] Class MockFor

- groovy.mock.interceptor.MockFor

- MockFor supports (typically unit) testing of classes in isolation by allowing a strictly ordered expectation of the behavior of collaborators to be defined. A typical test scenario involves a class under test (CUT) and one or more collaborators. In such a scenario it is often desirable to just test the business logic of the CUT. One strategy for doing that is to replace the collaborator instances with simplified mock objects to help isolate out the logic in the CUT. MockFor allows such mocks to be created using meta-programming. The desired behavior of collaborators is defined as a behavior specification. The behavior is enforced and checked automatically. With MockFor, a mock's expectation is always sequence dependent and its use automatically ends with a verify(). Typical usage is as follows:

       import groovy.mock.interceptor.MockFor

       class Person {
         String first, last
       }

       class Family {
         Person father, mother
         def nameOfMother() { "$mother.first $mother.last" }
       }

       def mock = new MockFor(Person)
       mock.demand.getFirst{ 'dummy' }
       mock.demand.getLast{ 'name' }
       mock.use {
         def mary = new Person(first:'Mary', last:'Smith')
         def f = new Family(mother:mary)
         assert f.nameOfMother() == 'dummy name'
       }

  Here, `Family` is our class under test and `Person` is the collaborator. We are using normal Groovy property semantics here; hence the statement `mother.last` causes a call to `mother.getLast()` to occur. The following features are supported:
  - typical mock style of failing early
  - mocks instance and class/static methods
  - mocks property access using normal getters and setters
  - mocks final methods and final Collaborators
  - mocks Groovy and Java Collaborators (Caller must normally be Groovy but see `proxyDelegateInstance()`)
  - can mock all objects of a given class (or a single Groovy object)
  - mocks even if Collaborator cannot be injected into the Caller
  - mocks even if Collaborator is not accessible on the Caller (no getter)
  - demanded calls specified via recording calls on the Demand object (EasyMock style).
  - cardinality specified as Integers or Ranges, default is 1..1; 'optional' can be achieved with 0..1
  - behavior specified via Closures, allowing static or calculated return values, throwing exceptions, asserting argument values, etc. (even tricky sequence constraints by sharing state in the testMethod scope between the behavior Closures)
  - matching parameter list specified via Closure's parameter list, supporting typed or untyped params, default params, and varargs.
  - not dependent on any external mock library
  - can mock constructors using an overloaded constructor for MockFor
  - can support an instance-style mode rather than the default behaviour-style mode using `proxyInstance()` and `proxyDelegateInstance()`
  - can support half-mocks using an `ignore` specification on the mock instead of a demand specification
  - can mock non-existing methods if desired
  See also: StubFor.
  Authors:
    Dierk Koenig
    Paul King

- - ### Properties Summary

    Properties
    Type | Name and description
    --- | ---
    `Class` | `clazz`
    `Demand` | `demand`
    `def` | `expect`
    `Ignore` | `ignore`
    `Map` | `instanceExpectations`
    `MockProxyMetaClass` | `proxy`

  - ### Constructor Summary

    Constructors
    Constructor and description
    `MockFor (Class clazz, boolean interceptConstruction = false)` The optional `interceptConstruction` flag allows mocking of constructor calls.

  - ### Methods Summary

    Methods
    Type Params | Return Type | Name and description
    --- | --- | ---
    `` | `static GroovyObject` | `getInstance(Class clazz, def args)`
    `` | `def` | `ignore(Object filter, Closure filterBehavior = null)` Allows particular method calls to be ignored and not treated as part of the required behavior specification.
    `` | `GroovyObject` | `makeProxyInstance(def args, boolean isDelegate)`
    `` | `GroovyObject` | `proxyDelegateInstance(def args = null)` Allows a more traditional instance-style mocking paradigm.
    `` | `GroovyObject` | `proxyInstance(def args = null)` Allows a more traditional instance-style mocking paradigm.
    `` | `void` | `use(Closure closure)` Identifies the Closure where the mocked collaborator behavior will be applied and verified.
    `` | `void` | `use(GroovyObject obj, Closure closure)`
    `` | `void` | `verify(GroovyObject obj)` If manual verification is required

  - ### Inherited Methods Summary

    Inherited Methods
    Methods inherited from class | Name
    --- | ---
    `class Object` | `wait, wait, wait, equals, toString, hashCode, getClass, notify, notifyAll`

- - ### Property Detail

    - #### Class clazz

    - #### Demand demand

    - #### def expect

    - #### Ignore ignore

    - #### Map instanceExpectations

    - #### MockProxyMetaClass proxy

  - ### Constructor Detail

    - #### MockFor(Class clazz, boolean interceptConstruction = false)

      The optional `interceptConstruction` flag allows mocking of constructor calls. These are represented in the demand specification using the class name as this example shows:

           import groovy.mock.interceptor.MockFor
           class Person {
             String first, last
           }
           def interceptConstructorCalls = true
           def mock = new MockFor(Person, interceptConstructorCalls)
           def dummy = new Person(first:'Tom', last:'Jones')
           mock.demand.with {
             Person() { dummy } // expect constructor call, return dummy
             getFirst() {'John'}
             getLast() {'Doe'}
           }
           mock.use {
             def p = new Person(first:'Mary', last:'Smith')
             assert p.first == 'John'
             assert p.last == 'Doe'
           }

  - ### Method Detail

    - #### static GroovyObject getInstance(Class clazz, def args)

    - #### def ignore(Object filter, Closure filterBehavior = null)

      Allows particular method calls to be ignored and not treated as part of the required behavior specification. If you don't specify a return closure the method call will fall through to the underlying instance, i.e. half-mock style. The `filter` object is invoked using the normal Groovy `isCase()` semantics. Here are some examples:

           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'
           }

      There is also a convenience form of ignore that matches the same style as demand. E.g. instead of `mock.ignore('hasNext')` you can use `mock.ignore.hasNext()`. A Closure variation is also provided. This convenience shorthand only applies to the `String` form of ignore and cannot be used with methods from `java.lang.Object`. Be careful using this feature while mocking some of the fundamental Java classes like `String` or `Pattern`. As these are used within the implementation of the ignore capability, strange behavior may be observed.

    - #### GroovyObject makeProxyInstance(def args, boolean isDelegate)

    - #### GroovyObject proxyDelegateInstance(def args = null)

      Allows a more traditional instance-style mocking paradigm. This is the recommended method to call to use the instance-style with Java classes. When mocking interfaces or abstract classes, a compatible proxy instance will be returned. When mocking Java classes, a compatible Groovy class will be generated and proxy instance returned. A MockProxyMetaClass will be instantiated for the class of the instance (i.e. may be on the generated class not the original class).

    - #### GroovyObject proxyInstance(def args = null)

      Allows a more traditional instance-style mocking paradigm. This is the recommended method to call to use the instance-style with Groovy classes. When mocking interfaces or abstract classes, a compatible proxy instance will be returned. When mocking Java classes, a compatible Groovy class will be generated and proxy instance returned. A MockProxyMetaClass will be instantiated for the original class. Typical example:

           import groovy.mock.interceptor.MockFor

           class Person {
             String first, last
           }

           class Family {
             Person mother, father
             String nameOfMother() { fullName(mother) }
             String nameOfFather() { fullName(father) }
             private fullName(p) { "$p.first $p.last" }
           }

           def mock = new MockFor(Person)
           mock.demand.with {
             getFirst{ 'dummy' }
             getLast{ 'name' }
           }
           Person john = mock.proxyInstance()
           Person mary = mock.proxyInstance()
           Family f = new Family(father:john, mother:mary)
           assert f.nameOfFather() == 'dummy name'
           assert f.nameOfMother() == 'dummy name'
           [john, mary].each{ mock.verify(it) }

      Normally for mocks, `verify()` is call automatically at the end of the "use" Closure, but with this style, no "use" Closure is present, so `verify()` must be called manually.

    - #### void use(Closure closure)

      Identifies the Closure where the mocked collaborator behavior will be applied and verified.

    - #### void use(GroovyObject obj, Closure closure)

    - #### void verify(GroovyObject obj)

      If manual verification is required