title: Using Spock to stub both Gorm and other methods in a Grails domain class
body: <p>Sorry if this is a newbie question but I would really appreciate any insights the community could offer with regard to a problem I am having with stubbing the following method which I have in a Grails service, LocationService.</p>
  
  <pre><code>Location locate(String target, String locator, Application app, boolean sync = true) {
      if (!target) throw new IllegalArgumentException("Illegal value for msid: " + target)
      def locRequest = Request.create(target, Type.LOCATE) 
      if (!locRequest.save()) {
              return Location.error(target, "Error persisting location request")
      }
      locationSource.locateTarget(target, locator, app, sync)
  }
  </code></pre>
  
  <p>I have a domain class, Request, that as well as the default GORM methods also has some extra domain methods, eg. the create() method below</p>
  
  <pre><code>@EqualsAndHashCode
  class Request {
  
      String reference
      String msid
      Type type
      Status status
      Destination destination
      DateTime dateCreated
      DateTime dateCompleted
  
      static create(String msid, Type type, Destination destination = Destination.DEFAULT) {
              new Request(reference: reference(type), type: type, status: Status.INITIATED, dateCreated: new DateTime())
      }
  </code></pre>
  
  <p>Finally, I have a Spock specification. I need to mock both the default GORM methods but also some stub some extra domain logic, eg, a static create method, in order to return a valid object to be persisted in the code under test.</p>
  
  <p>Ideally, I would use Spock mocks but I can't use them here as according to the post below from Peter N, they need to be injected into the caller and in this case the Request (which I am trying to mock), is created as a local variable in the locate method in LocationService:</p>
  
  <p><a href="https://groups.google.com/forum/?fromgroups=#!topic/spockframework/JemiKvUiBdo">https://groups.google.com/forum/?fromgroups=#!topic/spockframework/JemiKvUiBdo</a></p>
  
  <p>Nor can I use the Grails 2.x @Mock annotation as, although this will mock the GORM methods, I am unsure if i can mock/stub the additional static create() method from the Request class.</p>
  
  <p>Hence, finally, I have been trying to use the Groovy StubFor / MockFor methods to do this as I believe that these will be used in the call to the test method by wrapping it in a use closure (as below). </p>
  
  <p>Here is the test spec:</p>
  
  <pre><code>@TestFor(LocationService)
  // @Mock(Request)
  class LocationServiceSpec extends Specification {
  
      @Shared app = "TEST_APP"
      @Shared target = "123"
      @Shared locator = "999"
  
      def locationService = new LocationService()
      LocationSource locationSource = Mock()
  
  
    def "locating a valid target should default to locating a target synchronously"() {
        given:
              def stub = new StubFor(Request)
              stub.demand.create { target, type -&gt; new Request(msid: target, type: type) }
              stub.demand.save { true }
              1 * locationSource.locateTarget(target, locator, app, SYNC) &gt;&gt; { Location.create(target, point, cellId, lac) }
              def location
        when: 
              stub.use {
                  location = locationService.locate(target, locator, app)
              }
        then: 
              location
   }
  </code></pre>
  
  <p>However, when I run the test, although the stubbed create method returns my Request stub object, I get a failure on the stubbed save method:</p>
  
  <pre><code>groovy.lang.MissingMethodException: No signature of method:       com.domain.Request.save() is applicable for argument types: () values: []
  Possible solutions: save(), save(boolean), save(java.util.Map), wait(), last(), any()
  </code></pre>
  
  <p>Could anybody please point out what I am doing wrong here or suggest the best approach to solve my particular case if needing to stub additional methods as well as GORM methods of a domain class that I can't inject directly into the code under test?</p>
  
  <p>Thank you in advance,</p>
  
  <p>Patrick</p>