【问题标题】:Initialize Mocks in test before @BeforeStep在 @BeforeStep 之前初始化测试中的 Mocks
【发布时间】:2019-09-09 12:14:59
【问题描述】:

我有一个带有@BeforeStep 函数的自定义阅读器,用于初始化一些数据。这些数据来自外部数据库。

@Component
public class CustomReader implements ItemReader<SomeDTO> {

    private RestApiService restApiService;

    private SomeDTO someDTO;

    @BeforeStep
    private void initialize() {
        someDTO = restApiService.getData();
    }

    @Override
    public SomeDTO read() {
        ...    
        return someDTO
    }

}

在我的单元测试中,我需要模拟对外部数据库的调用。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = NedBatchApplication.class)
public class CustomReaderTest {

    @Autowired
    CustomReader customReader;

    @Mock
    RestApiService restApiService;

    @Before
    private void setup() {
        MockitoAnnotations.initMocks(this);
        ReflectionTestUtils.setField(customReader, "restApiService", restApiService);
        Mockito.when(restApiService.getData().thenReturn(expectedData);
    }
}

我面临的问题是@BeforeStep 在单元测试的@Before 之前执行,当我启动我的测试时。所以 restApiService.getData() 返回 null 而不是 expectedData。

有没有办法实现我想要的,或者我需要用不同的方法来实现它?

【问题讨论】:

    标签: java mockito spring-batch spring-boot-test


    【解决方案1】:

    经过与同事的反思后,他给了我一个解决方案:

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = NedBatchApplication.class)
    public class CustomReaderTest {
    
      CustomReader customReader;
    
      @Mock
      RestApiService restApiService;
    
      @Before
      private void setup() {
          MockitoAnnotations.initMocks(this);
          Mockito.when(restApiService.getData().thenReturn(expectedData);
    
          this.customReader = new CustomReader(restApiService);
      }
    
     @Test
     public void test() {
       customReader.initialize();
       (...)
     }
    }
    

    【讨论】:

      【解决方案2】:

      您确定BeforeStepBefore 注释之前运行(通过使用日志记录或类似方法?)。

      您的 Mockito 调用可能不完全正确。尝试改用Mockito.doReturn(expectedData).when(restApiService).getData()

      作为一种替代方法,如果 RestApiService 在您的自定义阅读器中自动装配,您将能够在测试中的自定义阅读器声明上使用 @InjectMocks 注释,这将导致您的 @ 的模拟版本987654326@在测试期间被注入到类中。

      【讨论】:

      • 是的,我确信 BeforeStep 在调试模式下使用 BreakPoints 在 Before 注释之前运行。
      • 因此,使用@Autowired 注释很可能会导致您的CustomReader 在运行测试的BeforeStep 之前完全初始化。您是否尝试过更改代码以使 RestAPIService 自动装配,从而允许您在测试中使用 @InjectMocks@MockBean 注释来模拟它?
      • 我会试一试,让您随时了解结果。感谢您的关心。
      • 我尝试了不同的方法。我将 initialize() 公开,并在 @Before 带注释的方法中创建了一个新的 CustomReader,例如 customReader = new CustomReader(restApiService)。然后在我的测试方法中我执行 customReader.initialize() 并且它可以工作。
      【解决方案3】:

      通常在使用基于 Spring 的测试时,尝试将诸如 restApiService(您要模拟的那些)之类的依赖项设置为 spring bean,然后您可以指示 spring 创建模拟并在应用程序上下文期间注入应用程序上下文借助@MockBean注解创建:

      import org.springframework.boot.test.mock.mockito.MockBean;  
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = NedBatchApplication.class)
      public class CustomReaderTest {
      
          @MockBean
          private RestApiService restApiService; 
      }
      

      【讨论】:

      • restApiService 使用@Service 进行注释。更改 @MockBean 中的 @Mock 不会改变结果。问题是BeforeStepBefore注释之前执行,女巫使restApiService.getData()return为null,我的读者在read()方法中也返回null。
      猜你喜欢
      • 2015-12-04
      • 2014-03-17
      • 2016-11-10
      • 2021-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多