首页 > 解决方案 > aop 方面作为春季测试中的模拟

问题描述

我偶然发现了一篇有趣的文章:AOP Aspects as mocks in JUnit

由于我需要模拟多个最终和私有静态变量,因此我计划使用 AOP 代替反射或 PowerMockito,因为它们会导致SpringJUnit4ClassRunner.

有什么方法可以@Aspect在不使用注释的情况下用于测试类@EnableAspectJAutoProxy?(我只想在一个测试用例中使用面向类 X 的方面。)

这是我想做的一个示例。

问题得到了回答(添加讨论可以做什么)

//External class 
public final class ABC(){
  public void method1() throws Exception {}
}
@Service
public void DestClass() {
  private static final ABC abc = new ABC();

  public Object m() {
    // code (...)
    try {
      abc.method1();
    }
    catch(Exception e) {
      // do something (...)
      return null;
    }
    // more code (...)
  }
}

标签: spring-mvcjunit4spring-aopspring-test

解决方案


Spring 框架允许以编程方式创建建议目标对象的代理,而无需通过@EnableAspectJAutoProxy或配置<aop:aspectj-autoproxy>

可以在文档部分找到详细信息:@AspectJ Proxies 的编程创建,实现非常简单。

文档中的示例代码。

// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);

// add an aspect, the class must be an @AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);

// you can also add existing aspect instances, the type of the object supplied must be an @AspectJ aspect
factory.addAspect(usageTracker);

// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();

请注意,使用 Spring AOP,只能建议方法执行。文档摘录

Spring AOP 当前仅支持方法执行连接点(建议在 Spring bean 上执行方法)。没有实现字段拦截,尽管可以在不破坏核心 Spring AOP API 的情况下添加对字段拦截的支持。如果您需要建议字段访问和更新连接点,请考虑使用 AspectJ 等语言。

与问题共享的文档是关于 aspectj 的,如果不提供要建议的示例代码,很难断定要求是否可以通过 Spring AOP 实现。该文件也提到了这一点。

AspectJ 集成的一个例子是 Spring 框架,它现在可以在其自己的 AOP 实现中使用 AspectJ 切入点语言。Spring 的实现并非专门针对测试解决方案

希望这可以帮助。

--- 更新:一个不使用 AOP 的测试用例 ---

考虑外部类

public class ABCImpl implements ABC{

    @Override
    public void method1(String example) {
        System.out.println("ABC method 1 called :"+example);
    }
}

DestClass

@Service
public class DestClass {

    private static final ABC service = new ABCImpl();

    protected ABC abc() throws Exception{
        System.out.println("DestClass.abc() called");
        return service;
    }

    public Object m() {
        Object obj = new Object();
        try {
            abc().method1("test");
        } catch (Exception e) {
            System.out.println("Exception : "+ e.getMessage());
            return null;
        }
        return obj;

    }
}

以下测试类使用重写的逻辑自动装配DestClassbean 以引发异常。可以修改此代码以适应您的要求。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { DestClassSpringTest.TestConfiguration.class })
public class DestClassSpringTest {

    @Configuration
    static class TestConfiguration {

        @Bean
        public DestClass destClass() {
            return new DestClass() {
                protected ABC abc() throws Exception {
                //  super.abc(); // not required . added to demo the parent method call
                    throw new Exception("Custom exception thrown");
                }
            };

        }
    }

    @Autowired
    DestClass cut;

    @Test
    public void test() {
        Object obj = cut.m();
        assertNull(obj);
    }
}

以下将是输出日志

DestClass.abc() called // this will not happen if the parent method call is commented in  DestClassSpringTest.TestConfiguration
Exception : Custom exception thrown

推荐阅读