I have a problem with understanding why the logic mocked inside @BeforeAll works, but only for the first test. They work fine separately, copying the identical logic to both tests will produce the same result – 1 passed, 1 failed. What happens: in AboutUsService.update() on the first line appears the mistake at
pageRepository.getByName(ABOUT_US_PAGE).orElseThrow(null);
For the first test, the calling of the method produces the expected result and returns AboutUsPage with its data. But for the next one it produces Optional.empty and NullPointerException eventually. What is the trick, why mocking works only for one test? Also, I checked out if the real repository is getting called, but it seems like something else caused it. Changing the annotation to @BeforeEach solves this problem, but shouldn’t it work as well with @BeforeAll? Spring Boot v. 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);
}
Advertisement
Answer
@BeforeAll
is executed once, before any test is executed. If you need logic that is executed before every test, use @Before