Skip to content
Advertisement

Spring Mockito @BeforeAll mocking logic works on 1 test only

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

2 People found this is helpful
Advertisement