mockito 使用SpringRunner进行单元测试spring重试时,Bean为空

anauzrmj  于 2022-12-18  发布在  Spring
关注(0)|答案(1)|浏览(145)

我尝试用springRunner为一个类写单元测试,但是我的@Autowired bean是空的,你能告诉我我做错了什么吗?
下面是我的测试类

@RunWith(SpringRunner.class)
@ContextConfiguration
public class DeltaHelperTest {

    @Autowired
    private DeltaHelper deltaHelper;
    
    @Before
    public void setUp() { System.setProperty("delta.process.retries", "2"); }

    @After
    public void validate() { validateMockitoUsage(); }

    @Test
    public void retriesAfterOneFailAndThenPass() throws Exception {
        when(deltaHelper.restService.call(any(), any())).thenThrow(new HttpException());
        deltaHelper.process(any(),any());
        verify(deltaHelper, times(2)).process(any(), any());
    }

    @Configuration
    @EnableRetry
    @EnableAspectJAutoProxy(proxyTargetClass=true)
    @Import(MockitoSkipAutowireConfiguration.class)

    public static class Application {

        @Bean
        public DeltaHelper deltaHelper() {
            DeltaHelper deltaHelper = new DeltaHelper();
            deltaHelper.myStorageService= myStorageService();
            deltaHelper.restService = restService();
            return deltaHelper;
        }

        @Bean
        public MyStorageService myStorageService() {
            return new MyStorageService();
        }

        @Bean
        public MyRestService restService() {
            return new MyRestService();
        }

        @Bean
        public MyRepo myRepository() {
            return mock(MyRepo.class);
        }
    }

    @Configuration
    public static class MockitoSkipAutowireConfiguration {
        @Bean MockBeanFactory mockBeanFactory() {
            return new MockBeanFactory();
        }
        private static class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
            @Override
            public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
                return !mockingDetails(bean).isMock();
            }
        }
    }
}

此处测试服务在deltaHelper对象上为null。
MyRepo.class被嘲笑,因为它有一些更多的@autowired bean引用
在此处附加其他类

@Component
public class DeltaHelper {

    @Autowired
    MyRestService restService;

    @Autowired
    MyStorageService myStorageService;

    @NotNull
    @Retryable(
            value = Exception.class,
            maxAttemptsExpression = "${delta.process.retries}"
    )
    public String process(String api, HttpEntity<?> entity) {
            return restService.call(api, entity);
    }
    @Recover
    public String recover(Exception e, String api, HttpEntity<?> entity) {

            myStorageService.save(api);
            return "recover";
    }
}

@Service
public class MyStorageService {

    @Autowired
    MyRepo myRepo;

    @Async
    public MyEntity save(String api) {
        return myRepo.save(new MyEntity(api, System.currentTimeMillis()));
    }
}


public class MyRestService extends org.springframework.web.client.RestTemplate {
}

谢谢
尝试使用MockitoJUnitRunner,但发现@Retryable仅在使用Spring运行时有效

zynd9foi

zynd9foi1#

我不知道你为什么要测试框架功能,比如retry,一般来说,你可以假设框架组件已经被框架作者彻底测试过了。
忽略这一点,我至少可以看到两个问题:

  1. deltaHelper不是模拟,而是您的SUT,但您尝试设置方法调用。如果您模拟SUT,则不再测试您的类,而是测试模拟。如果您希望调用失败,请不要模拟调用,而是模拟其依赖项(例如MyRestService restService),并让对依赖项的调用抛出异常。
    1.在真实的方法调用(“act”部分)中传递ArgumentMatchers.any(),但是any()无条件返回null(不是某个魔术对象)。如果要对SUT进行操作,必须传递实值。any用于设置模拟或验证对模拟的调用。
    为了完整起见,下面是any()的源代码:
public static <T> T any() {
    reportMatcher(Any.ANY);
    return null;
}

相关问题