модульный тест завершается неудачно, если объект члена журнала (@ Slf4j не найден groovy.lang.MissingPropertyException: такого свойства нет: журнал для класса: - PullRequest
0 голосов
/ 05 июня 2019

Я помогаю моей команде разработчиков с некоторым кодом регистрации в нашей среде.

с использованием весеннего AOP Я создал классный класс, называемый LoggingAspect.Его основная цель - записывать время выполнения методов для классов в каталогах com.zions.comon.services.logging и снабжать их комментариями @ Loggable.

Поскольку некоторые классы уже имеют журналирование @ sl4j, мне нужно определить, нет ли в журнале члена журнала.объекты существуют и используют встроенную регистрацию @ slf4j для этого класса.Если это не так, мне нужно выполнить аннотацию @ sl4j в коде регистрации аспектов.

Первый оператор в блоке try проверит, существует ли элемент журнала для объекта.Если это так, то iLog будет настроен на регистратор входящего объекта.Однако я не уверен, как завершить остальную часть кода, как только я обнаружу объект члена журнала.Я не ожидаю, что кто-то напишет этот код для меня, но был бы признателен за любые предложения / области исследования о том, как это сделать - например, использование «если»

Логика должна выглядеть примерно так:

  1. Перехватывать и вычислять время ведения журнала метода в выбранных классах
  2. Проверять существующий объект члена журнала, который указывает, что @ slf4j уже присутствует в классе
  3. Если объект члена журнала завершается, используйте ведение журнала @ sl4jфункции, уже встроенные в этот класс
  4. Если объект-член журнала не существует, используйте @ slf4j, регистрируясь в журнале Аспект-код.

любая помощь будет оценена

https://imgur.com/VIXAf4q.jpg "схема потока регистрации"

Возвращенный код к исходной версии - код My LoggingAspect на данный момент выглядит следующим образом

package com.zions.common.services.logging

import groovy.util.logging.Slf4j
import org.slf4j.Logger
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.EnableAspectJAutoProxy

@Aspect
@Configuration
@Slf4j
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class LoggingAspect {
     * 
     * This is a Logging Aspect for the Loggable annotation that calculates method runtimes
     * for all methods under classes annotated with @Loggable*/

    /**
     * Logs execution time of method under aspect.
     * 
     * @param joinPoint - method under join
     * @return actual return of method under join point.
     * @throws Throwable
     */
    @Around('execution (* *(..)) && !execution(* *.getMetaClass()) && @within(com.zions.common.services.logging.Loggable)')
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {

                def obj = joinPoint.this
                Logger iLog = log
                long start = System.currentTimeMillis();
                Object proceed = joinPoint.proceed();
                long executionTime = System.currentTimeMillis() - start;

                try {

                    /*First statement of try block attempts to test if log members exist on object.
                     If it does, then iLog will get set to incoming object's logger*/

                    obj.log.isInfoEnabled()
                    iLog = obj.log
                } catch (e) {}

                iLog.info("${joinPoint.getSignature()} executed in ${executionTime}ms");
                return proceed;
            }
        }

Если это полезномоя запись в журнале:

package com.zions.common.services.logging

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/* Logging annotation to be used at class level
 * Loggable annotation for all methods of a class annotated with the @Loggable annotation*/

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Loggable {}

Я добавил тестовый класс junit, который проверяет, когда член журнала найден - строка 'iLog = obj.log' get вызывается из кода LoggingAspect и т.st is PASSING.

LoggingAspectSpecification.groovy

package com.zions.common.services.logging

import static org.junit.Assert.*

import groovy.util.logging.Slf4j
import org.junit.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Profile
import org.springframework.context.annotation.PropertySource
import org.springframework.test.context.ContextConfiguration

import spock.lang.Specification

@ContextConfiguration(classes=[LoggingAspectSpecificationConfig])
class LoggingAspectSpecification extends Specification {

    @Autowired
    SomeClass someClass

    def 'Main flow for timing log'() {
        setup: 'class to be logged'

    when: 'execute something with class testing log'
    someClass.methodOne()
    someClass.methodTwo()

    then: 'validate something logged'
    true
    }

}


@TestConfiguration
@Profile("test")
@ComponentScan(["com.zions.common.services.logging"])
@PropertySource("classpath:test.properties")
class LoggingAspectSpecificationConfig {

    @Bean
    SomeClass someClass() {
        return new SomeClass()
    }

}

@Loggable
@Slf4j
class SomeClass {

    def methodOne() {
        log.info('run methodOne')

    }

    def methodTwo() {
        log.info('run methodTwo')
    }
}

Однако мой модульный тест не выполняется с классами, которые не имеют @ Slf4j, что означает, что он будет выполняться с регистраторомаспект вместо объекта pointcut.Полная трассировка ошибок:

groovy.lang.MissingPropertyException: No such property: log for class: com.zions.common.services.logging.SomeClass2
    at com.zions.common.services.logging.SomeClass2.methodOne(LoggingAspectSpecification2.groovy:55)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:747)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
    at com.zions.common.services.logging.LoggingAspect.logExecutionTime(LoggingAspect.groovy:42)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:643)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:632)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:174)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
    at com.zions.common.services.logging.LoggingAspectSpecification2.Main flow for timing log(LoggingAspectSpecification2.groovy:27)

Второй код модульного теста приведен ниже - (единственное отличие состоит в том, что @ Slf4j) отсутствует в классах.

LoggingAspectSpecification2.groovy

    package com.zions.common.services.logging

    import static org.junit.Assert.*
    import groovy.util.logging.Log    
    import groovy.util.logging.Slf4j
    import org.junit.Test
    import org.springframework.beans.factory.annotation.Autowired
    import org.springframework.boot.test.context.TestConfiguration
    import org.springframework.context.annotation.Bean
    import org.springframework.context.annotation.ComponentScan
    import org.springframework.context.annotation.Profile
    import org.springframework.context.annotation.PropertySource
    import org.springframework.test.context.ContextConfiguration

    import spock.lang.Specification

    @ContextConfiguration(classes=[LoggingAspectSpecificationConfig2])
    class LoggingAspectSpecification2 extends Specification {

        @Autowired
        SomeClass2 someClass2

        def 'Main flow for timing log'() {
            setup: 'class to be logged'

        when: 'execute something with class testing log'
        someClass2.methodOne()
        someClass2.methodTwo()

        then: 'validate something logged'
        true
        }

    }

<!-- language: lang-groovy -->

    @TestConfiguration
    @Profile("test")
    @ComponentScan(["com.zions.common.services.logging"])
    @PropertySource("classpath:test.properties")
    class LoggingAspectSpecificationConfig2 {

        @Bean
        SomeClass2 someClass2() {
            return new SomeClass2()
        }

    }

<!-- language: lang-groovy -->

    @Loggable


class SomeClass2 {
        def methodOne() {

            int  x=10, y=20;
            System.out.println(x+y+" testing the aspect logging code");

        }

        def methodTwo() {
           int  x=10, y=20;
           System.out.println(x+y+" testing the aspect logging code");
        }
    }

Я предполагаю, что что-то не так в моем коде LoggingAspect в блоке Try Catch?

1 Ответ

0 голосов
/ 17 июня 2019

Чтобы устранить ошибку и заставить мой модульный тест пройти без @ Slf4j или @Log - мне пришлось добавить оператор println в код SomeClass2, как в,

    int  x=10, y=20;
    System.out.println(x+y+" testing the apsect logging code");

добавление @Log просто дало ему еще один встроенный элемент журнала, похожий на @ Slf4j - добавление оператора println и удаление аннотации @Log заставили выполнить код LoggingAspect. Модульный тест проходит.

...