Spring Mockito @BeforeAll 模拟逻辑仅适用于 1 个测试
Spring Mockito @BeforeAll mocking logic works on 1 test only
我无法理解为什么 @BeforeAll 中模拟的逻辑有效,但仅适用于第一次测试。
它们分别工作得很好,将相同的逻辑复制到两个测试将产生相同的结果——1 个通过,1 个失败。 发生了什么: in AboutUsService.update() 第一行出现错误在
pageRepository.getByName(ABOUT_US_PAGE).orElseThrow(null);
对于第一个测试,调用该方法会产生预期的结果,returns AboutUsPage 及其数据。但是对于下一个它会产生 Optional.empty
和 NullPointerException 最终。诀窍是什么,为什么模拟仅适用于一次测试?
另外,我检查了是否调用了真正的存储库,但似乎是其他原因造成的。
将注释更改为 @BeforeEach 可以解决这个问题,但它不应该与 @BeforeAll 一起工作吗? Spring 引导版本 2.3.4
@SpringBootTest(classes = {AboutUsService.class, AboutUsPageRepository.class,
AboutUsPageImageStore.class, ImageUtil.class})
@TestInstance(Lifecycle.PER_CLASS)
public class AboutUsServiceTest {
@Autowired
private AboutUsService aboutUsService;
@MockBean
private AboutUsPageRepository pageRepository;
@MockBean
private AboutUsPageImageStore aboutUsPageImageStore;
@MockBean
private ImageUtil imageUtil;
@BeforeAll
public void configure() {
when(pageRepository.getByName(anyString()))
.thenReturn(Optional.of(AboutUsTestData.getAboutUsPage()));
when(aboutUsPageImageStore.setContent(any(AboutUsPageImage.class), any(Resource.class)))
.thenReturn(new AboutUsPageImage());
}
@Test
public void updateWithImagesTest() {
when(imageUtil.fileIsValid(any(MultipartFile.class)))
.thenReturn(true);
MultipartFile validFile = new MockMultipartFile("name", "etc", "content", "Hello".getBytes());
aboutUsService.update(new MultipartFile[]{validFile});
verify(pageRepository, times(1)).save(any(AboutUsPage.class));
}
@Test
public void updateWithNoImagesTest() {
AboutUsPage updated = aboutUsService.update(new MultipartFile[0]);
AboutUsPage expected = AboutUsTestData.getAboutUsPage();
assertSame(expected.getImages().size(), updated.getImages().size());
}
}
@Service
@AllArgsConstructor
@Slf4j
public class AboutUsService {
public static final String ABOUT_US_PAGE = "ABOUT_US_PAGE";
private final AboutUsPageImageStore pageImageStore;
private final ImageUtil imageUtil;
private final AboutUsPageRepository pageRepository;
@Transactional
public AboutUsPage update(MultipartFile[] images) {
AboutUsPage page = pageRepository.getByName(ABOUT_US_PAGE).orElseThrow(null);
if (ArrayUtils.isNotEmpty(images)) {
List<AboutUsPageImage> pageImages = new ArrayList<>();
Arrays.stream(images).forEach(extraImage -> {
if (imageUtil.fileIsValid(extraImage)) {
AboutUsPageImage infoImage = new AboutUsPageImage();
pageImageStore.setContent(infoImage, extraImage.getResource());
infoImage.setPage(page);
pageImages.add(infoImage);
}
});
if (CollectionUtils.isNotEmpty(pageImages)) {
page.setImages(pageImages);
}
return pageRepository.save(page);
} else {
return page;
}
}
}
@Repository
public interface AboutUsPageRepository extends JpaRepository<AboutUsPage, Long> {
Optional<AboutUsPage> getByName(String name);
}
@BeforeAll
在执行任何测试之前执行一次。如果您需要在每次测试之前执行的逻辑,请使用 @Before
我无法理解为什么 @BeforeAll 中模拟的逻辑有效,但仅适用于第一次测试。 它们分别工作得很好,将相同的逻辑复制到两个测试将产生相同的结果——1 个通过,1 个失败。 发生了什么: in AboutUsService.update() 第一行出现错误在
pageRepository.getByName(ABOUT_US_PAGE).orElseThrow(null);
对于第一个测试,调用该方法会产生预期的结果,returns AboutUsPage 及其数据。但是对于下一个它会产生 Optional.empty 和 NullPointerException 最终。诀窍是什么,为什么模拟仅适用于一次测试? 另外,我检查了是否调用了真正的存储库,但似乎是其他原因造成的。 将注释更改为 @BeforeEach 可以解决这个问题,但它不应该与 @BeforeAll 一起工作吗? Spring 引导版本 2.3.4
@SpringBootTest(classes = {AboutUsService.class, AboutUsPageRepository.class,
AboutUsPageImageStore.class, ImageUtil.class})
@TestInstance(Lifecycle.PER_CLASS)
public class AboutUsServiceTest {
@Autowired
private AboutUsService aboutUsService;
@MockBean
private AboutUsPageRepository pageRepository;
@MockBean
private AboutUsPageImageStore aboutUsPageImageStore;
@MockBean
private ImageUtil imageUtil;
@BeforeAll
public void configure() {
when(pageRepository.getByName(anyString()))
.thenReturn(Optional.of(AboutUsTestData.getAboutUsPage()));
when(aboutUsPageImageStore.setContent(any(AboutUsPageImage.class), any(Resource.class)))
.thenReturn(new AboutUsPageImage());
}
@Test
public void updateWithImagesTest() {
when(imageUtil.fileIsValid(any(MultipartFile.class)))
.thenReturn(true);
MultipartFile validFile = new MockMultipartFile("name", "etc", "content", "Hello".getBytes());
aboutUsService.update(new MultipartFile[]{validFile});
verify(pageRepository, times(1)).save(any(AboutUsPage.class));
}
@Test
public void updateWithNoImagesTest() {
AboutUsPage updated = aboutUsService.update(new MultipartFile[0]);
AboutUsPage expected = AboutUsTestData.getAboutUsPage();
assertSame(expected.getImages().size(), updated.getImages().size());
}
}
@Service
@AllArgsConstructor
@Slf4j
public class AboutUsService {
public static final String ABOUT_US_PAGE = "ABOUT_US_PAGE";
private final AboutUsPageImageStore pageImageStore;
private final ImageUtil imageUtil;
private final AboutUsPageRepository pageRepository;
@Transactional
public AboutUsPage update(MultipartFile[] images) {
AboutUsPage page = pageRepository.getByName(ABOUT_US_PAGE).orElseThrow(null);
if (ArrayUtils.isNotEmpty(images)) {
List<AboutUsPageImage> pageImages = new ArrayList<>();
Arrays.stream(images).forEach(extraImage -> {
if (imageUtil.fileIsValid(extraImage)) {
AboutUsPageImage infoImage = new AboutUsPageImage();
pageImageStore.setContent(infoImage, extraImage.getResource());
infoImage.setPage(page);
pageImages.add(infoImage);
}
});
if (CollectionUtils.isNotEmpty(pageImages)) {
page.setImages(pageImages);
}
return pageRepository.save(page);
} else {
return page;
}
}
}
@Repository
public interface AboutUsPageRepository extends JpaRepository<AboutUsPage, Long> {
Optional<AboutUsPage> getByName(String name);
}
@BeforeAll
在执行任何测试之前执行一次。如果您需要在每次测试之前执行的逻辑,请使用 @Before