嘲笑春豆的方法行为打破了方面



我搜索了SO,发现了一堆其他看起来相似但不完全一样的问题,所以我会问另一个问题。

我有 Spring 应用程序,并说我创建了自定义方面(寻找CatchMe注释(以特定方式记录异常。我想通过模拟我的 Spring @Service 类方法之一的行为来测试方面,以便在调用时抛出异常。然后在另一个方法中,用我的自定义注释@CatchMe进行注释,我调用第一个方法。我希望发生的是被记录的异常。不幸的是,抛出了异常,但未触发方面。那么,如何使用 Mockito 在此测试中触发方面呢?

注意:我已经检查了这些(还有更多(:

  • 单元测试 Spring @Around AOP 方法
  • 弹簧方面在单元测试中未触发
  • 弹簧:无法将模拟注入带有@Aspect注释的类

但其中大多数与控制器相关,而不是与服务相关,我只想测试服务。

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {BeanConfig.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();
    }
}

服务业

@Service
public class MyService {
    @Autowired
    private MyServiceDependency serviceDep;
    @CatchMe
    public void execute() {
        serviceDep.process();
    }
}

@Service
public class MyServiceDependency {
    public Object process() {
        // may throw exception here
    }
}

配置和方面

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

@Aspect
@Component
public class CatchMeAspect {
    @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 {}

编辑:该功能有效,但我想通过测试进行验证。

实际上它

正在按预期工作,但是您正在运行基于代理的AOP的副作用,尤其是在这种情况下基于类的代理。

当前,您是在代理上设置字段

,而不是在代理内的实际对象上设置字段。这才是你真正想要的。若要获取实际实例,请使用 AopTestUtils.getUltimateTargetObject,然后在 ReflectionTestUtils.setField 方法中使用它。

@Autowired
@InjectMocks
private MyService service;
@Mock
private MyServiceDependency serviceDep;
@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
    MyService serviceToInject = AopTestUtils.getUltimateTargetObject(service);
    ReflectionTestUtils.setField(serviceToInject, "serviceDep", serviceDep);
}

但是我认为这种方法是错误的,当你开始像这样胡闹时,有更好的方法。只需使用弹簧注入模拟。为此测试用例创建特定的@Configuration类。使其成为内部public static class,并为依赖项添加一个模拟@Bean

@Configuration
@Import(BeanConfig.class) 
public static class TestBeanConfig {
    @Bean
    public MyServiceDependency myServiceDependency() {
        return Mockito.mock(MyServiceDependency.class);
    }
}

现在,在您的测试类中,您可以简单地@Autowire两个 bean,而不需要使用反射或其他任何东西来设置依赖项。

@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
    @Autowired
    private MyService service;
    @Autowired
    private MyServiceDependency 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();
    }
}

这将处理正确的依赖项。

我遇到了与@nyxz相同的问题,这是故意的,请参阅 https://github.com/spring-projects/spring-boot/issues/7243。

受到 Deinum @M启发,以下解决方案在 Spring Boot 2.3.4.RELEASE 和 JUnit 5 中为我工作。我们只会提供一个模拟的豆子,没有@MockedBean

@SpringBootTest
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class MyServiceTest {
    @Autowired
    private MyService service;
    @Test
    public void test() {
        service.execute();
    }
    static class TestBeanConfig {
         @Bean
         @Primary
         public MyServiceDependency myServiceDependency() {
             MyServiceDependency myServiceDependency = Mockito.mock(MyServiceDependency.class)
             // Add behavior of mocked bean here
             return myServiceDependency;
         }
    }
}

相关内容

  • 没有找到相关文章

最新更新