jeudi 4 février 2016

Mocking Spring bean's method behavior breaks aspects

I searched SO and found bunch of other questions that looked similar but not exactly, so I'll ask another one.

I have Spring application and say I created custom aspect (looking for CatchMe annotation) to log exceptions in a specific way. I want to test the aspect by mocking the behavior of one of my Spring @Service class's method so it throws exception when it is called. Then in another method, annotated with my custom annotation @CatchMe, I call the first method. What I expect to happen is the exception to get logged. Unfortunatelly the exception is thrown but the aspect is not triggered. So how can I make the aspect to get triggered in this test using Mockito?

Note: I've checked those (plus a bunch more):

but most of them are Controller related and not Service related and I want to test only the service.

The Test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfig.class})
public class MyServiceTest {

    @Autowired
    @InjectMocks
    private MyService service;

    @Mock
    private MyServiceDependency serviceDep;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        ReflectionTestUtils.setField(service, "serviceDep", serviceDep);
    }

    @Test
    public void test() {
        when(serviceDep.process()).thenAnswer(new Answer<Object>() {

                @Override
                public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                    throw new Exception("Sample message.");
                }

            });

        service.execute();
    }
}

Services

@Service
public class MyService {

    @Autowired
    private MyServiceDependency serviceDep;

    @CatchMe
    public void execute() {
        serviceDep.process();
    }
}


@Service
public class MyServiceDependency {

    public void process() {
        // may throw exception here
    }
}

Configuration and Aspect

@Configuration
@ComponentScan(
        basePackages = {"com.example.config"},
        excludeFilters = {@Filter(Configuration.class)})
@Import({BeanConfig.class})
public class TestConfig {}

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"com.example.services"})
public class BeanConfig { .. }


@Aspect
@Component
public class DbErrorRetryAspect {

    @Around("@annotation(CatchMe)")
    public Object catchMe(final ProceedingJoinPoint pjp) throws Throwable {
        try {
            pjp.proceed();
        } catch (Throwable t) {
            // fency log
        }

    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CatchMe {}

Aucun commentaire:

Enregistrer un commentaire