2

I 've trying to test a service which uses hibernate envers to perform a rollback. Everything is working fine but the test is driving me mad.

This is the beginning of the service:

@Slf4j
@AllArgsConstructor
@Service
public class ObjectRollbackServiceImpl implements ObjectRollbackService {

  @Autowired
  private EntityManager entityManager;

  @Autowired private ObjectRollbackRepository objectRollbackRepository;

  private void restorePreviousVersionOfObject(Long id, Boolean isDelete) {

    AuditReader auditReader = AuditReaderFactory.get(entityManager);

    List<Number> revNumbers = auditReader.getRevisions(ObjectEntity.class, id); 

And this is the test:

class ObjectRollbackServiceTests {

  private static final Long objectId = 1L;
  @InjectMocks
  ObjectRollbackServiceImpl objectRollbackServiceImpl;
  @Mock
  ObjectRollbackRepository objectRollbackRepository;

  @PersistenceUnit
  private EntityManagerFactory entityManagerFactory;


  @Mock
  AuditReader auditReader;


  @BeforeEach
  void setUp() throws Exception {
    MockitoAnnotations.openMocks(this);

  }

  @Test
  void testRestorePreviousVersionOfEditedObjectOk() {
    ObjectEntity object = ObjectEntity.builder().build();
    List<Number> listRevisions = Lists.newArrayList();
    listRevisions.add(1);

    when(auditReader.getRevisions(any(), any(Long.class))).thenReturn(listRevisions);
    when(auditReader.find(any(), any(Long.class), any(Number.class))).thenReturn(object);
    when(objectRollbackRepository.findById(any(Long.class))).thenReturn(Optional.of(object));
    when(objectRollbackRepository.saveAndFlush(any(ObjectEntity.class))).thenReturn(object);
    doNothing().when(objectRollbackRepository).updateAuditDates(any(ZonedDateTime.class)
    , any(Integer.class)
    , any(AuditorBO.class)
    , any(Long.class));

    doNothing().when(objectRollbackRepository).deleteRevisionsNotEqualsToCurrentAndPrevious(any(Integer.class), any(Long.class));

    assertDoesNotThrow(() -> objectRollbackServiceImpl.restorePreviousVersionOfEditedObject(1L));


  }



}

So the problem is that entityManager is null when trying to execute this line:

AuditReader auditReader = AuditReaderFactory.get(entityManager);

What am I missing?

Rachel
  • 65
  • 11

3 Answers3

2

You are using @AllArgsConstructor so it is creating behind the scenes a constructor with the following signature:

ObjectRollbackServiceImpl(EntityManager entityManager,
                          ObjectRollbackRepository objectRollbackRepository)

So when you use @InjectMocks it expects you to mock the parameters of the constructor:

@Mock
EntityManager entityManager;
@Mock
ObjectRollbackRepository objectRollbackRepository;
@InjectMocks
ObjectRollbackServiceImpl objectRollbackServiceImpl;
Alex Blasco
  • 793
  • 11
  • 22
1

you autowired the entityManager. when you apply @PersistenceUnit on entityManager fields it tries to create the real instance. But we need a mock instance. Apply @Mock and try.

hariprasad
  • 26
  • 2
  • I have changed to Mock but it shows the next error: org.opentest4j.AssertionFailedError: Unexpected exception thrown: org.hibernate.envers.exception.AuditException: Hibernate EntityManager not present! – Rachel Jan 04 '23 at 13:48
  • you could try this: reference: https://stackoverflow.com/questions/51963750/not-able-to-mock-persistencecontext-in-spring-boot-test – hariprasad Jan 04 '23 at 14:02
0

You can try mocking AuditReaderFactory.get to give you the mocked AuditReader instance.

See this question with its answers for further reference.

So, in your case it could look something like this (code adapted from one of the answers to the other question):

  @Test
  public void testStaticMockWithVerification() {
    try (MockedStatic<AuditReaderFactory> dummy = Mockito.mockStatic(AuditReaderFactory.class)) {
      dummy.when(() -> AuditReaderFactory.get(Mockito.any(EntityManager.class)))
        .thenReturn(auditReader);

      factory.getConnection();

    }
  }

And instead of using the @Mock annotation, probably create the Mock ObjectRollbackServiceImpl instance in some setup method or static initialization block, so you can set this static mock up beforehand.

kutschkem
  • 7,826
  • 3
  • 21
  • 56