2013-03-21 11 views
8

Scusate se questa è una domanda per principianti ma apprezzerei davvero qualsiasi intuizione che la community potrebbe offrire in merito a un problema che sto riscontrando con il seguente metodo avere in un servizio Grails, LocationService.Utilizzo di Spock per lo stub di Gorm e di altri metodi in una classe di dominio Grails

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

ho una classe di dominio, richiesta, che i metodi così come predefinito Gorm ha anche alcuni metodi di dominio in più, per esempio. il metodo create() sotto

@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()) 
    } 

Infine, ho una specifica Spock. Ho bisogno di prendere in giro entrambi i metodi GORM predefiniti, ma anche alcuni stub della logica di dominio extra, ad esempio, un metodo di creazione statica, al fine di restituire un oggetto valido da mantenere nel codice sotto test.

Idealmente, vorrei usare Spock Mock ma non posso usarli qui come in base al post sottostante di Peter N, devono essere iniettati nel chiamante e in questo caso la Richiesta (che sto cercando di deridere), viene creato come una variabile locale nel metodo individuare in LocationService:

https://groups.google.com/forum/?fromgroups=#!topic/spockframework/JemiKvUiBdo

né posso usare il 2.x @Mock annotazioni Grails come, anche se questo deridere i metodi Gorm, non sono sicuro se posso simulare/stubare il metodo statico aggiuntivo create() dalla classe Request.

Quindi, alla fine, ho cercato di utilizzare i metodi Groovy StubFor/MockFor per farlo, poiché credo che verranno utilizzati nella chiamata al metodo di test avvolgendolo in una chiusura di utilizzo (come di seguito).

Ecco le specifiche di prova:

@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 -> new Request(msid: target, type: type) } 
      stub.demand.save { true } 
      1 * locationSource.locateTarget(target, locator, app, SYNC) >> { Location.create(target, point, cellId, lac) } 
      def location 
     when: 
      stub.use { 
       location = locationService.locate(target, locator, app) 
      } 
     then: 
      location 
} 

Tuttavia, quando si esegue il test, anche se la contuso creare metodo restituisce la mia richiesta oggetto stub, ottengo un guasto sulla stubbed metodo di salvataggio:

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() 

Qualcuno potrebbe indicare cosa sto facendo male qui o suggerire l'approccio migliore per risolvere il mio caso particolare se ha bisogno di stub metodi aggiuntivi e metodi GORM di una classe di dominio che non posso iniettare direttamente nel codice sotto test?

Grazie in anticipo,

Patrick

risposta

8

Credo che si dovrebbe essere in grado di utilizzare Grails' @Mock annotazione come lei ha citato per i metodi Gorm, e quindi è necessario prendere in giro manualmente i metodi statici:

@TestFor(LocationService) 
@Mock(Request)// This will mock the GORM methods, as you suggested 
class LocationServiceSpec extends Specification { 
... 
    void setup() { 
     Request.metaClass.static.create = { String msid, Type type, Destination destination = Destination.DEFAULT -> 
      //Some logic here 
     } 
    } 
... 

Quando si utilizza il @Mock annotazione, Grails si deridere i metodi predefiniti (salvare/get/cercatori dinamiche), ma non fare nulla per eventuali ulteriori metodi potrebbe essere aggiunto, quindi è necessario manu alleati quelli.

+0

Grazie GrailsGuy. Questo ha risolto il mio problema. Stavo entrando in un po 'di groviglio tra l'uso di '@ Mock' per prendere in giro i metodi predefiniti e come sovrascrivere manualmente metodi aggiuntivi. Usando '@ Mock' mi ha dato il primo ma non il secondo. E usare StubFor mi ha dato il secondo, ma non il primo. Ma non sembravano funzionare insieme. Tuttavia, usando '@ Mock' per il primo e modificando la metaClass per ottenere che quest'ultimo risolva perfettamente il problema. Grazie molto. – Paddy

+1

@Paddy Nessun problema, felice di poterti aiutare! – Igor

+1

@Igor Dovrebbe essere "Request.metaClass.static.create ..." Questo è quello che ha funzionato per me! – Champ