Search code examples
javaspringjunitmockitospring-aop

Spring AOP AfterThrowing aspect doesn't work with mock objects in Junit 5


in my spring project I created simple aspect which catches DaoExceptions and turns them into service exceptions

@Aspect
@Component
public class ExceptionAspect {

    @Pointcut("execution(public * *(..))")
    private void allPublicMethods() {

    }
    
    @Pointcut("within(img.imaginary.dao.*)")
    private void inDao() {

    }
    
    @AfterThrowing(pointcut = "allPublicMethods() && inDao()", throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint, DaoException exception) {
        throw new ServiceException(String.format("%s in method %s %s class", exception.getMessage(),
                joinPoint.getSignature().getName(), joinPoint.getTarget().getClass().getSimpleName()), exception);
    }  
}

and it works fine when DaoException throwing from dao layer to service it turns into Service exception

but only not in the tests:

@Test
void findById_ShouldThrowServiceException_WhenEntityNotFound() {
    Mockito.when(defaultDao.findById(0)).thenThrow(DaoException.class);        
    assertThrows(ServiceException.class, () -> defaultServiceImpl.findById(0));
}

in this test I have a defaultDao and it is a Mock object and when it throws a DaoException my aspect does not catch and proxy it

I can't figure out how to solve this problem


Solution

  • With the following assumptions - it is a spring-boot project , defaultDao is a mocked bean using @MockBean

    Do go through the issue to understand why @MockBean will not work.

    Following code would mock a bean and throw an exception . You will need to adjust the code to make it work for you.( eg: @SpringBootTest may or may not be required for your case ).

    @SpringBootTest
    class DefaultDaoTest {
    
        @Autowired
        DefaultDao defaultDao;
    
        @Test
        void test() {
            assertThrows(ServiceException.class, () -> defaultDao.findById(0));
        }
    
    }
    
    @Configuration
    class TestConfig {
        @Bean
        @Primary
        public DefaultDao defaultDao() {
            return new DefaultDao() {
                @Override
                public Object findById(Long id) {
                    throw new DaoException();
                }
            };
        }
    }