【问题标题】:Disabling certain aspects during unit test runs在单元测试运行期间禁用某些方面
【发布时间】:2011-11-18 00:27:44
【问题描述】:

我有集成测试(加载上下文)和单元测试一起运行。我的代码使用spring进行aspectj编译时编织。

我的问题是我声明的建议也在我的一些单元测试期间运行。这扼杀了单元测试的概念,这就是我想禁用它们的原因。

我可以在切入点声明、我可以调用的一些方法、一些 spring 配置或 maven 命令中添加一些东西来禁用这些建议,例如所有 *UnitTest.java 吗?

感谢您的帮助。


示例:

我有以下单元测试:

@RunWith(MockitoJUnitRunner.class)
public class CompanyServiceImplTest {
    @Test
    public void createCampaignTest() throws Exception {
        when(companyDaoMock.saveCompany(any(Campaign.class))).thenReturn(77L);

        Long campaignId = companyService.createCampaign(campaignMock);

        assertEquals(Long.valueOf(77L), Long.valueOf(campaignId));
    }
}

及以下服务方式:

@Override
@Transactional
@EventJournal(type = EventType.CAMPAIGN_CREATE, owner = EventOwner.TERMINAL_USER)
public Long createCampaign(Campaign campaign) {
    return companyDao.saveCompany(campaign);
}

方面:

@Aspect
public class EventJournalAspect {

    @Autowired
    private EventJournalService eventJournalService;

    @Pointcut(value="execution(public * *(..))")
    public void anyPublicMethod() {}

    @Pointcut("within(com.terminal.service..*)")
    private void inService() {}

    @AfterReturning(pointcut = "anyPublicMethod() && inService() && @annotation(eventJournal) && args(entity,..)", returning = "id")
    public void process(Object id, EventJournal eventJournal, AbstractDomainEntity entity)
            throws Throwable {
        if (eventJournal.type() != EventType.CAMPAIGN_PAYMENT || id != null) {
            saveEvent(eventJournal, EventStatus.SUCCESS, entity, (Long) id);
        }
    }

    @AfterThrowing(pointcut = "anyPublicMethod() && inService() && @annotation(eventJournal) && args(entity,..)", throwing="ex")
    public void processException(EventJournal eventJournal, AbstractDomainEntity entity, Exception ex) throws Throwable {
        saveEvent(eventJournal, EventStatus.FAILURE, entity, null);
    }

    private void saveEvent(EventJournal eventJournal, EventStatus status, AbstractDomainEntity entity, Long persistentId)   {
        EventType type = eventJournal.type();
        EventOwner owner = eventJournal.owner();
        eventJournalService.saveEvent(type, owner, EventStatus.SUCCESS, entity, persistentId);
    }

}

当测试执行时 - eventJournalService 为空。因此我看到NullPointerException

【问题讨论】:

    标签: java spring unit-testing aspectj spring-aop


    【解决方案1】:

    我只能猜测: 首先是要有一个单独的Spring applicationContext-test.xml, 没有组件扫描; 在 maven 中,您可以添加一个阶段运行时,不包括用于测试的编织 jar。

    【讨论】:

      【解决方案2】:

      编译时编织会将通知调用内联到您拥有的切入点标识的目标方法中。我个人觉得在编译时编织到位的情况下进行单元测试很好,因为在运行时您的单元确实包含带有内联建议的类?

      我必须不包含建议的想法是有两个不同的编译目标,一个带有编译时编织,一个没有,您应该能够通过 maven 配置文件、一个不编织建议的开发配置文件和一个prod profile 来编织各个方面。

      【讨论】:

        【解决方案3】:

        答案很简单:您想使用if() pointcut expression


        更新(在问题也被更新后):上面最初提供的链接应该包含足够的信息,但是对于它的价值,一个简短的解释和一个简单的例子:

        if() 切入点是返回 booleanstatic 方面方法。如果返回值为true,则表示只要myPointcut()匹配,任何像myPointcut() && if()这样的组合切入点都匹配。对于 false 的返回值,整个组合切入点不匹配,从而有效地停用了与切入点相关的任何建议。

        那么你可以在静态if() 切入点中做什么?

        • 评估某个工具类的静态布尔成员,例如 TestMode.ACTIVE,这仅在单元测试或集成测试期间为真
        • 评估仅在测试期间设置的环境变量
        • 评估仅在测试期间设置的 Java 系统属性
        • 还有更多

        如果你想做一些更花哨(和更复杂)的事情并且性能不是那么重要,你也可以尝试动态确定自动连接的方面成员变量是否等于 null 并且只有在注入的对象是时才激活你的切入点实际存在。这里唯一的问题是如何从静态方法中确定成员变量。我不知道 Spring AOP,但是在普通的 AspectJ 中有一个帮助类 Aspects 和几个名为 aspectOf(..) 的重载方法。假设您的方面被实例化为单例,您可以执行以下操作:

        @Pointcut("if()")
        public static boolean isActive() {
            return Aspects.aspectOf(PerformanceMonitorAspect.class).eventJournalService != null;
        }
        
        // ...
        
        @AfterReturning(pointcut = "isActive() && anyPublicMethod() && inService() && @annotation(eventJournal) && args(entity,..)", returning = "id")
        // ...
        
        @AfterThrowing(pointcut = "isActive() && anyPublicMethod() && inService() && @annotation(eventJournal) && args(entity,..)", throwing="ex")
        // ...
        

        【讨论】:

        • 请提供示例
        • 我已在原帖中添加了详细信息。
        • 你怎么能在你不是原始发帖人的问题中添加细节?
        • 我有同样的问题。我提供了尊重问题作者描述的代码。我觉得您的回答是正确的,但您回答中的信息不足以(对我来说)了解如何解决问题。我提供了具体的代码。我希望你能帮助我进行具体的修复。我相信这绝对是SO风格。我看过几篇您提供此答案的帖子,因此我相信您知道。
        • 我可以创建单独的主题,但它会被复制。如您所见,没有人支持答案,但有 4 个人对问题感兴趣。因此,SO 听觉的答案可以得到改善。
        【解决方案4】:

        如果当前执行是使用 JUnit 框架启动的,您可以编写一个返回的方法。

        该方法可以使用 Thread.currentThread().getStackTrace() 检查堆栈跟踪并搜索 MockitoJUnitRunner 是否存在。

        我使用 SpringJUnit4ClassRunner 测试了这个解决方案,但我认为可以使用 MockitoJUnitRunner。

        另外,您可以有一个静态布尔字段,例如:

        private static boolean TEST_ENVIRONMENT = false;
        

        在您的项目中存在的类中(而不是在您的测试中)并检查控制方法中的值,而不是使用堆栈跟踪。

        运行测试时,可以使用@BeforeClass 注解设置 TEST_ENVIRONMENT = true。

        此解决方案仅让您了解您的代码是否正在通过测试运行。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-08-06
          • 1970-01-01
          • 2014-02-24
          • 1970-01-01
          • 1970-01-01
          • 2010-12-16
          • 2013-12-05
          • 2011-08-13
          相关资源
          最近更新 更多