当前位置: 首页 > 面试题库 >

用于AspectJ的JUnit测试

太叔小云
2023-03-14
问题内容

我正在尝试为自定义方面编写Junit测试。这是Aspect类代码片段:

@Aspect
@Component
public class SampleAspect {

    private static Logger log = LoggerFactory.getLogger(SampleAspect.class);

    @Around("execution(* org.springframework.data.mongodb.core.MongoOperations.*(..)) || execution(* org.springframework.web.client.RestOperations.*(..))")
    public Object intercept(final ProceedingJoinPoint point) throws Throwable {
        logger.info("invoked Cutom aspect");
         return point.proceed();

    }

}

因此,只要关节点与切入点匹配,上述方面就会截获。它的工作正常。

但是我的问题是如何对该类进行单元测试。我有以下Junit测试:

@Test(expected = MongoTimeoutException.class)
    public void TestWithMongoTemplate() {
        //MongoDocument class
        TestDocument test = new TestDocument();

        ApplicationContext ctx = new AnnotationConfigApplicationContext(TestMongoConfigurationMain.class);
        MongoTemplate mongoTemplate = ctx.getBean(MongoTemplate.class);

        //this call is being intercepted by SampleAspect
        mongoTemplate.save(test);

    }

因此,我mongoTemplate.save(test)在Junit中SampleAspect匹配切入点时被其拦截。但是,SampleAspect当调用该联合点时,我应该如何确定(可能是通过断言)我正在拦截?

我不能断言返回值,intercept()因为它除了执行联合点外没有其他特殊之处。因此,无论是按方面执行还是基于返回值的常规执行,我的Junit都找不到任何区别。

如果提供了方面测试的任何代码片段示例,那就更好了。


问题答案:

我认为您要测试的是方面编织和切入点匹配。请注意,这将是集成而不是单元测试。如果您真的要对方面逻辑进行单元测试,并且因为无论如何都已用“
mockito”标记了问题,我建议您这样做:编写一个单元测试,并模拟方面的联接点和它的其他参数(如果有)。这是一个稍微复杂的示例,其中包含一些内部检查逻辑:

按方面定位的Java类:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        new Application().doSomething(11);
        new Application().doSomething(-22);
        new Application().doSomething(333);
    }

    public void doSomething(int number) {
        System.out.println("Doing something with number " + number);
    }
}

被测方面:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class SampleAspect {
    @Around("execution(* doSomething(int)) && args(number)")
    public Object intercept(final ProceedingJoinPoint thisJoinPoint, int number) throws Throwable {
        System.out.println(thisJoinPoint + " -> " + number);
        if (number < 0)
            return thisJoinPoint.proceed(new Object[] { -number });
        if (number > 99)
            throw new RuntimeException("oops");
        return thisJoinPoint.proceed();
    }
}

运行时的控制台日志Application.main(..)

如您所见,方面通过11,否定-22并抛出333的异常:

execution(void de.scrum_master.app.Application.doSomething(int)) -> 11
Doing something with number 11
execution(void de.scrum_master.app.Application.doSomething(int)) -> -22
Doing something with number 22
execution(void de.scrum_master.app.Application.doSomething(int)) -> 333
Exception in thread "main" java.lang.RuntimeException: oops
    at de.scrum_master.aspect.SampleAspect.intercept(SampleAspect.aj:15)
    at de.scrum_master.app.Application.doSomething(Application.java:10)
    at de.scrum_master.app.Application.main(Application.java:7)

方面的单元测试:

现在,我们真的要验证方面是否能够完成应做的工作并涵盖所有执行路径:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import static org.mockito.Mockito.*;

public class SampleAspectTest {
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Mock
    private ProceedingJoinPoint proceedingJoinPoint;

    private SampleAspect sampleAspect = new SampleAspect();

    @Test
    public void testPositiveSmallNumber() throws Throwable {
        sampleAspect.intercept(proceedingJoinPoint, 11);
        // 'proceed()' is called exactly once
        verify(proceedingJoinPoint, times(1)).proceed();
        // 'proceed(Object[])' is never called
        verify(proceedingJoinPoint, never()).proceed(null);
    }

    @Test
    public void testNegativeNumber() throws Throwable {
        sampleAspect.intercept(proceedingJoinPoint, -22);
        // 'proceed()' is never called
        verify(proceedingJoinPoint, never()).proceed();
        // 'proceed(Object[])' is called exactly once
        verify(proceedingJoinPoint, times(1)).proceed(new Object[] { 22 });
    }

    @Test(expected = RuntimeException.class)
    public void testPositiveLargeNumber() throws Throwable {
        sampleAspect.intercept(proceedingJoinPoint, 333);
    }
}

现在运行此简单的JUnit + Mockito测试,以隔离地测试方面逻辑, 而不是 布线/编织逻辑。对于后者,您将需要另一种类型的测试。

PS:仅为您使用了JUnit和Mockito。通常,我只使用Spock及其内置的模拟功能。;-)



 类似资料:
  • 问题内容: 我在一个项目中工作,我们必须为我们所有的简单bean(POJO)创建单元测试。如果POJO由getter和setter组成,那么是否有必要为其创建单元测试?假设POJO大约100%的时间都可以正常工作吗? 问题答案: TDD中的规则是“测试所有可能破坏的东西” 吸气剂可以破坏吗?通常不会,因此我不必费心测试。此外,我的代码 做 测试肯定会调用吸气所以它 会 被测试。 我个人的规则是,我

  • 问题内容: 我需要为设计欠佳的旧应用程序编写JUnit测试,并且正在向标准输出中写入许多错误消息。当方法正确运行时,它将返回XML响应: 但是,当XML格式错误或无法理解请求时,它将返回并将某些内容写入标准输出。 有什么方法可以在JUnit中声明控制台输出?要捕获类似的情况: 问题答案: 使用和很简单: 样本测试案例: 我使用此代码测试了命令行选项(断言-version输出版本字符串等)

  • DAO类的相关方面如下 我的src/test/resources/application.properties文件如下所示 在Eclipse中作为JUnit测试运行的跟踪 应用程序结构 -SRC ----application.java ----COM ----Hitstpa ----application.properties --测试 ---爪哇

  • 我正在尝试从Spring Boot应用程序中的JUnit中访问application.properties或application-test.properties。 com.myservice.config.AppConfig: 主/资源/应用程序.属性: test.resources/application-test.properties JUnit类可以从main/resources/appl

  • 问题内容: 我正在对项目上的纯Java文件运行纯JUnit4 Java测试,但是如果不手动将其公开,我将找不到一种清晰使用@VisibleForTesting的方法。 例如: 方法必须是使其对测试“公开”,但是在那种情况下,注释没有意义吗?如果批注什么也不做,为什么不只使用注释呢? 问题答案: 标签本身可以帮助短绒棉子识别不需要的访问。 为了降低使用风险直接,添加此方法是在 科特林 或在 Java

  • 似乎我在Spring 4.1.17中使用Spring Boot1.2.6.RELEASE做的任何事情都不起作用。我只想访问应用程序属性并在必要时使用test覆盖它们(无需使用hack手动注入Property tySource) 这不工作... 这也不是. 也不是这个... 完整的测试用例... 导致 似乎3.x和4.x之间有很多相互矛盾的信息,我找不到任何可以肯定的东西。 如有任何见解,将不胜感激