2011-12-15 9 views
9

que tienen una clase de usuario, como por ejemplo:¿Cómo probar los controladores de unidad que usan springSecurityService?

class User { 
    transient springSecurityService 
    String displayName 
    String password 
<snip> 
    protected void encodePassword() { 
     password = springSecurityService.encodePassword(password) 
    } 
} 

Y un UserController. estoy tratando de escribir pruebas unitarias para el UserController sin embargo yo estoy recibiendo este error para guardar, actualizar y eliminar pruebas:

java.lang.NullPointerException: Cannot invoke method encodePassword() on null object 

¿Qué tengo que configurar de la manera de burlarse de conseguir que esto ¿trabajo?

He intentado muchas combinaciones de código de burla, como las siguientes, pero estoy perdido.

defineBeans { 
    springSecurityService(SpringSecurityService) 
} 

Cualquier consejo sería muy apreciado.

+0

que estoy experimentando el mismo problema exacto. Por lo que puedo ver, defineBeans() debería funcionar, de acuerdo con la documentación. Lamentablemente, no tiene ningún efecto. –

Respuesta

0

lo he hecho así:

protected void encodePassword() { 
     // SpringSecutiryService is not injected in tests. 
     if (springSecurityService) 
      password = springSecurityService.encodePassword(formPassword) 
    } 
+2

No es una solución ideal, se parece más a una solución para pasar las pruebas. ¿Qué pasa si el servicio de seguridad es anulado por alguna razón extraña en la producción ... Entonces todas sus contraseñas no se convierten en hash (sin un mensaje de error) – david

+0

Tiene razón @david. –

8

Yo personalmente no me gusta la adición lógica para el código de producción para ayudar a satisfacer una prueba. A veces debes tomar una decisión sobre qué es lo mejor para hacer. Par de opciones ...

  1. La respuesta anterior funcionará, pero como ya he dicho personalmente no preferiría
  2. no lo hacen prueba de la unidad. Escriba todas las pruebas que se encuentran en esta situación como pruebas de integración.
  3. Disfrútalo con un servicio falso.

Si este código (o código que corre el mismo problema) se rocía en su aplicación, probablemente querrá encontrar una manera de simular estas llamadas en sus pruebas unitarias para todos los casos de prueba para que No estás duplicando tus esfuerzos de configuración en todas partes. Una forma fácil de burlarse de esto es con metaClassing.

@Test 
public void something() { 
    def user = ... 
    def springSecurityService = new Object() 
    springSecurityService.metaClass.encodePassword = {String password -> "ENCODED_PASSWORD"} 
    user.springSecurityService = springSecurityService 
    ... 
} 

Ahora cuando el springSecurityService.encodePassword se invoca que deben regresar "ENCODED_PASSWORD". También creo un Object en vez de instanciar un nuevo SpringSecurityService porque si crea una instancia de un servicio real, puede terminar llamando métodos reales en ese servicio de forma inesperada y sin saberlo y haciendo que sus pruebas pasen por los motivos equivocados. Prefiero obtener un error de método que no sea una prueba de aprobación que no debe pasar.

+0

¡Buena respuesta! Por cierto, corregí la línea "service.metaClass.encodePassword =" a "springSecurityService.metaClass.encodePassword =" – david

-1

En mi caso traté de anular la implementación de encodePassword() de SecUser, que llama a springSecurityService.encodePassword().

me sorprendió porque necesitaba sustituir la clase y la instancia (si no deroga ninguna, se produce un error):

SecUser.metaClass.encodePassword = { 'a' } 
user.metaClass.encodePassword = { 'b' } 

alguna idea de por qué necesito esto?

0

Creo que lo correcto es burlarnos del servicio. Deberá probar los diferentes casos que pueden ser el valor de retorno y que el valor correcto se transfiere al método de servicio.

@Test 
public void something() { 
    def user = ... 
    def expectedPassword = 'mock encoded pass' 
    controller.springSecurityService = [encodePassword: { String passwd -> return expectedPassword }] 

    ... 
} 

o

@Test 
public void something() { 
    def user = ... 
    def expectedPassword = 'mock encoded pass' 
    def mockSecurityService = mockFor(SpringSecurityService) 
    mockSecurityService.demand.encodePassword { String passwd -> return expectedPassword} 
    controller.springSecurityService = mockSecurityService.createMock() 

    ... 
    mockSecurityService.verify() // throws exception if demands aren't met 
} 
Cuestiones relacionadas