2013-09-21 16 views
5

Ho un metodo privato che è stato deriso in Grails 1.3.7 usando metaclass ma ora che ho aggiornato la versione grails alla 2.2.4, lo stesso mocking ha esito negativo.Come imitare i metodi privati ​​nel controller in grails 2.2.4

Metodo di prova ha una chiamata al metodo privato

private def MyPrivateMeth1(def arg1, def arg2) { 
... 
} 

Mocking è qualcosa di simile

MyController.metaClass.private.MyPrivateMeth1 = { a, b -> 
... 
} 

risposta

0

Credo che non è necessario la parte .private.

MyController.metaClass.MyPrivateMeth1 = { a, b -> ... } 

dovrebbe essere sufficiente, tuttavia specificherò esplicitamente i tipi di parametro

E, a proposito, si dovrebbe tenere convenzioni di denominazione del Java - Metodi di nomi devono iniziare con carattere minuscolo

+1

ho provato, ma non sembra funzionare ... qualsiasi altra cosa mi manca? – user1298426

0

per i test unitari ho usato riflessione per i metodi privati. Qualcosa di simile a questo dovrebbe funzionare ...

Method method = BehaviourService.getDeclaredMethod("behaviourValidConstraints",User.class,Behaviour.class) 
method.setAccessible(true) 
boolean valid = ((Boolean)method.invoke(service, user,b)).booleanValue() 

In primo luogo si ottiene il metodo con l'impostazione getDeclaredMethod il nome e il tipo di parametro, lo si imposta accessibile e, infine, tou chiama con method.invoke passare l'oggetto che ha la metodo e i parametri. Il risultato è un oggetto quindi devi lanciarlo.

So che ci deve essere una soluzione migliore, ma questo è l'unico che ho trovato che funziona

Edit: Siamo spiacenti, ciò che è al di sopra è per effettuare una chiamata ad un metodo privato. Penso che ho preso in giro un metodo privato, prima solo facendo ...

MyController.metaClass.myPrivateMeth1 { a, b -> 
... 
} 

Proprio come hai scritto, ma senza la .private e il segno =. Inoltre, come ha detto Kamil, dovresti seguire le convenzioni di denominazione java per i nomi dei metodi ...

+0

Questo chiamerà il metodo privato che è nella mia classe controller, non è vero? Voglio prendere in giro questo metodo piuttosto che chiamarlo. – user1298426

+0

È vero, scusa, ho frainteso la domanda ... – Eylen

1

Sembra che sia necessario dichiarare tipi di argomenti di chiusura (il 100% se tali argomenti hanno tipi effettivi, ad esempio Long, ma non sicuro di DEF, ma è necessario provare):

MyController.metaClass.MyPrivateMeth1 = { def a, def b -> ... } 
+0

ya ... l'ho provato ma non sembra funzionare .... ho anche provato \t \t def strict = mockFor (MyController) strictControl.demand.MyPrivateMeth1 {User a, Account b -> .... \t \t} – user1298426

6

prova usando l'annotazione @TestFor, che vi darà una variabile di controllo. È quindi possibile modificare il metaclesso di quello, nonché incorporare i suggerimenti di Kamil Mikolajczyk e araxn1d. Quindi, tutto il tuo test dovrebbe probabilmente simile a questa:

@TestFor(MyController) 
class MyControllerTests { 

    setup() { 
     controller.metaClass.MyPrivateMeth1 = {def arg1, def arg2 -> 
      //you can make your mocked method return whatever you wish here 
      return [key1: "foo", key2: "bar"] 
     } 
    } 
    void testForSomething() { 
     //Some code here that invokes an action or two in your controller which in turn invokes the private method 
    } 
} 

Assicurarsi di avere DEF (o String, Long, o qualunque dichiarazione si utilizza) sugli argomenti di tuo metodo di finto proprio come sono sulla metodo privato effettivo nel controller o il test proverà a utilizzare prima il normale metodo privato della classe.

Ecco un test simile a Spock:

import spock.lang.Specification 
import spock.lang.Unroll 
import grails.test.mixin.* 
import org.junit.* 
@TestFor(MyController) 
class MyControllerSpec { 

    def "test that thing"() { 
     setup: 
      controller.metaClass.MyPrivateMeth1 = {def arg1, def arg2 -> return someOutput } 
     expect: 
      controller.someAction() == expectedRender 
     where: 
      someOutput        | expectedRender 
      [key1: "foo", key2: "bar"]    | "expected render from controller" 
    } 
} 
+0

Potete fornire il modo per restituire una mappa dal metodo di controllo fittizio. così facendo ricevo alcune eccezioni –

+0

Nel mio esempio precedente, someOutput è la variabile restituita dal metodo del controller deriso. Nel mio esempio in cui clausola, l'ho impostato su una stringa, ma lo si poteva facilmente impostare su una mappa. Aggiornerò l'esempio – jonnybot

Problemi correlati