spock icon indicating copy to clipboard operation
spock copied to clipboard

Detached Spock Mock with Groovy Closures initialisation

Open mettyoung opened this issue 2 years ago • 1 comments

Is your feature request related to a problem?

We have been using Spock framework in writing our test suite and it saves us a lot of the Java boilerplate using Groovylang. However, we had to repeatedly write the same mocks in different application services.

A common approach in JUnit was to write mock helpers where test fixtures are defined. This makes it cheaper to write unit tests.

However, I am aware detached mocks should be attached to a specification in order to use interactions. This makes writing mock fixtures not possible, such as:

class DetachedMockFactorySpec extends Specification {
  def test() {
    given:
    def sut = new SubjectUnderTest(MockUtils.defaultMockCustomerRepository())
    
    then:
    ...
  }

Currently, I know we can write detached mocks as follows:

interface IMockMe {
  int foo(int i)
}

class DetachedMockFactorySpec extends Specification {

  @Subject
  DetachedMockFactory factory = new DetachedMockFactory()

  def "Mock(class)"() {
    given:
    IMockMe mock = factory.Mock(IMockMe)
    attach(mock)
    mock.foo(_) >> 2

    expect:
    mock.foo(2) == 2

    cleanup:
    detach(mock)
  }
}

Describe the solution you'd like

Is it possible to write it as?

class DetachedMockFactorySpec extends Specification {

  // DetachedMockApi acts as a proxy
  @Subject
  DetachedMockApi mock = new DetachedMockApi(new DetachedMockFactory(), this)

  def "Mock(class)"() {
    given:
    // attach and detach is called internally by the proxy api
    IMockMe mock = mock.Mock(IMockMe)
    mock.foo(_) >> 2

    expect:
    mock.foo(2) == 2
  }
}

Describe alternatives you've considered

No response

Additional context

No response

mettyoung avatar Aug 01 '23 13:08 mettyoung

@mettyoung I am not sure if this would help you, but there is the @spock.mock.AutoAttach annotation, which would do the required attach/detach for you, when you annotate the field containing the mock. So if you do something like:


class DetachedMockFactorySpec extends Specification {
  @AutoAttach
  def yourMock = MockUtils.defaultMockCustomerRepository()

  def test() {
    given:
    def sut = new SubjectUnderTest(yourMock )
    
    then:
    ...
  }

You should be able to use the mock.

As a hint the PR #1728 will add documentation regarding the DetachedMockFactory and the use with @AutoAttach.

AndreasTu avatar Aug 02 '23 11:08 AndreasTu