2012-08-06 16 views
5

Actualmente estoy trabajando en una herramienta de supervisión que utiliza aspectj. Debido a que esta herramienta debe ser independiente de la tecnología (en la medida de lo posible), no estoy usando Spring para inyección. Pero quiero que mis aspectos sean sometidos a pruebas unitarias.Cómo burlarse de un aspecto

ejemplo Aspecto:

@Aspect 
public class ClassLoadAspect { 
    private Repository repository; 

    public ClassLoadAspect() { 
     repository = OwlApiRepository.getInstance(); 
    } 

    @After("anyStaticInitialization()") 
    public void processStaticInitilization(JoinPoint jp) { 
     Class type = jp.getSourceLocation().getWithinType(); 
     if (type.isInterface()) { 
      repository.storeInterfaceInitialization(type); 
     } else if (type.isEnum()) { 
      repository.storeEnumInitialization(type); 
     } else { 
      repository.storeClassInitialization(type); 
     } 

    } 

    @Pointcut("staticinitialization(*) && !within(cz.cvut.kbss.odra..*)") 
    public void anyStaticInitialization() { 
    } 

    public Repository getRepository() { 
     return repository; 
    } 

    public void setRepository(Repository repository) { 
     this.repository = repository; 
    } 
} 

Sin embargo, yo realmente no sé, cómo construir unidad de prueba (el campo repositorio debería ser burlado (usando Mockito)), pero no tengo la creación de aspecto bajo control, por lo tanto, No puedo configurar la dependencia de forma manual. ¿A qué debo llamar para obtener la instancia? O hay algún otro escenario de cómo evaluar los aspectos aspectj de la unidad.

Gracias.

Respuesta

2

Usted dice que encuentre su propia manera de introducir el objeto de burla hacky. ¿Qué es exactamente lo que te disgusta y cómo te lo imaginas? Solo puedo adivinar:

¿No le gusta el hecho de que reemplace globalmente las llamadas a OwlApiRepository.getInstance() en su meta aspecto? Posteriormente, se podría restringir específicamente inyección objeto de burla al constructor de aspecto (estoy usando la sintaxis AspectJ nativa porque me siento incómodo con el estilo de anotación POJO):

public privileged aspect ClassLoadTestAspect { 
    static boolean active = true; 

    declare precedence : ClassLoadTestAspect, ClassLoadAspect; 
    pointcut classLoadAspect() : 
     if(active) && 
     withincode(ClassLoadAspect.new()) && 
     call(* OwlApiRepository.getInstance()); 

    Object around() : classLoadAspect() { 
     return new MockRepository(); 
    } 
} 

Como también se puede ver, esta variante de un meta (aspecto -test) también tiene un interruptor para encenderlo y apagarlo a voluntad. Quizás esto también era algo que no te gustaba. Como dije, estoy adivinando. Después de sus comentarios, podría responder más específicamente.

Editar: En cuanto a sus preocupaciones, creo que los he abordado en la medida de lo posible:

  • que no es necesario un soporte simulacro.

  • El aspecto se puede (de) activar. Sería fácil hacer que su activación dependa de otras condiciones, por lo que solo está activo en su entorno de prueba. Si esto aún no es suficiente, utilice el tejido en tiempo de compilación para sus aspectos de producción y el entrelazado en tiempo de carga para su aspecto de prueba. De esta forma, su código de bytes ni siquiera estará presente en su entorno de producción.

  • Mi versión no reemplaza nada a nivel mundial, pero como un buen cirujano, solo corta de forma mínimamente invasiva exactamente en un solo lugar.

  • Realmente no puedo entender su preocupación sobre la manipulación del código byte por varias razones: usted usa AspectJ, es decir, la manipulación del código inherentemente byte (tejido). Usas Mockito que crea clases en tiempo de ejecución. Tampoco entiendo dónde ves una deficiencia en AspectJ. No ha explicado cómo desea que se comporte el "medio estándar del lenguaje" o qué interfaz debe proporcionar para la prueba. Incluso si lo hubiera hecho, no puedo cambiar el idioma (AJ) y la herramienta (Mockito) de su elección.

+0

Lo que no me gusta en mi solución: la sustitución global del método estático hace que sea difícil para poner a prueba - Me debe restablecer el simulacro repositorio manualmente (en lugar de establecer una nueva). También tuve que intruducir un titular falso para obtener acceso al objeto de repositorio simulado. La tercera cosa es que no me gusta templarme con el bytecode para establecer el simulacro, realmente creo que esto tiene que hacerse por medios estándar del lenguaje (si no es posible, muestra una deficiencia en el aspecto). diseño). Pero desde el código, su solución podría hacer (al menos no necesita el titular) :-). – malejpavouk

+0

Punto tomado, la generosidad es tuya. Gracias :-) – malejpavouk

+0

Perdón por el ruido. He decidido agregar los comentarios a mi respuesta porque la cantidad de caracteres disponibles para los comentarios era demasiado pequeña. Pero gracias de todos modos por otorgarme la recompensa. :) – kriegaex

1

puede dividir sus pruebas. Primero prueba la lógica del aspecto. es un pojo puedes probarlo como quieras. la segunda parte está probando los puntos de corte. en este caso, cree otro aspecto simple con los mismos puntos de corte (por ejemplo, extráigalos como una constante). tal vez hay algunas herramientas de prueba dedicado, pero no estoy al tanto de cualquier y era la manera más fácil que vienen a la mente

1

Mi solución actual es la introducción de este AspectJ hackear con el fin de reemplazar el método de fábrica únicos

@Aspect 
public class MockingAspect { 

    @Around("call(synchronized static OwlApiRepository *(..))") 
    public OwlApiRepository processGetInstance(ProceedingJoinPoint jp) {  
     System.out.println("getting mock"); 
     return MockHolder.getMock(); 
    } 
} 
0

¿Qué tal algo en esta línea? Básicamente, continúe manteniendo su aspecto, en el aspecto interior delegue el comportamiento a otra interfaz, y se burle de esa interfaz para sus pruebas, en lugar de burlarse del aspecto en sí. Aquí es un pseudocódigo:

public interface ClassLoadHelper{ 
    void processStaticInitialization(Class<?> clazz); 
} 

public class ClassLoadHelperImpl implements ClassLoadHelper{ 
    private Repository repository; 

    public ClassLoadHelperImpl() { 
     repository = OwlApiRepository.getInstance(); 
    } 

    void processStaticInitialization(Class<?> clazz){ 
     if (type.isInterface()) { 
      this.repository.storeInterfaceInitialization(type); 
     } else if (type.isEnum()) { 
      this.repository.storeEnumInitialization(type); 
     } else { 
      this.repository.storeClassInitialization(type); 
     }   
    } 
} 


@Aspect 
public class ClassLoadAspect { 
    private ClassLoadHelper classLoadHelper; 


    @After("anyStaticInitialization()") 
    public void processStaticInitilization(JoinPoint jp) { 
     Class<?> type = jp.getSourceLocation().getWithinType(); 
     this.classLoadHelper.processStaticInitialization(type); 

    } 

    @Pointcut("staticinitialization(*) && !within(cz.cvut.kbss.odra..*)") 
    public void anyStaticInitialization() { 
    } 

    public ClassLoadHelper getClassLoadHelper() { 
     return classLoadHelper; 
    } 

    public void setClassLoadHelper(ClassLoadHelper classLoadHelper) { 
     this.classLoadHelper = classLoadHelper; 
    } 
} 

Ahora en su prueba se puede hacer esto:

ClassLoadAspect.aspectOf().setClassLoadHelper(mockClassLoadHelper); 
1

¿Quiere pruebas de unidades, correcto? Esta es una prueba de unidad pequeña para probar una anotación personalizada con aspectos con el fin de envolver un throwable en una excepción de aplicación personalizada. (TestNG + Mockito)

public class ResourceApplicationExceptionAspectTest { 
@Mock 
private ProceedingJoinPoint pjp; 
@Mock 
private ResourceApplicationException resourceApplicationException; //annotation definition 

@BeforeMethod 
public void setUp() throws Exception { 
    MockitoAnnotations.initMocks(this); 

} 

@Test(groups ="unit", expectedExceptions = ResourceApplicationException.class) 
public void testWrapExceptionAdvice() throws Throwable { 

    ResourceApplicationExceptionAspect aspect = new ResourceApplicationExceptionAspect(); 

    when(pjp.proceed()).thenThrow(new NullPointerException()); 
    aspect.wrapExceptionAdvice(pjp, resourceApplicationException); 
}