Home > OS >  JUnit test is with inconsistent data during findAll and findById
JUnit test is with inconsistent data during findAll and findById

Time:10-04

I'm trying to test the repository layer of a user implementing JpaRepository having the following test class:

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

@ExtendWith({MockitoExtension.class, SpringExtension.class})
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserRepositoryTest {
    @Autowired
    private UserRepository userRepository;

    @BeforeEach
    void initUseCase() {
        User user1 = new User(null, "First N1", "Last N1", "[email protected]", "password", UserRole.USER,
                null,
                false, true);
        User user2 = new User(null, "First N2", "Last N2", "[email protected]", "password", UserRole.USER,
                null,
                false, true);
        User user3 = new User(null, "First N3", "Last N3", "[email protected]", "password", UserRole.USER,
                null,
                false, true);

        List<User> users = Arrays.asList(user1, user2, user3);
        userRepository.saveAllAndFlush(users);
    }

    @AfterEach
    public void destroyAll(){
        userRepository.flush();
        userRepository.deleteAll();
    }

//     READ
    @Test
    @Transactional
    void testFindById_Success() {
        assertTrue(userRepository.findById(1L).isPresent());
        assertEquals("First N1", userRepository.findById(1L).get().getFirstName());
    }

    @Test
    @Transactional
    void testFindAll_Success() {
        assertEquals(3, this.userRepository.findAll().size());
    }

    // CREATE
    @Test
    @Transactional
    void testCreateUser_Success() {
        User user =
                new User(4L, "First N4", "Last N4", "[email protected]", "password", UserRole.USER, null, true, true);
        userRepository.save(user);

        assertEquals(4, userRepository.findAll().size());
    }
}

If I run all of them one by one, all three pass. Once I've run the class as one whole the one with FindById always fails as it shows the item is not found. Can someone explain why it behaves like this and what I'm doing wrong?

enter image description here

CodePudding user response:

First of all, JUnit methods won't follow the declaration sequence of the test method. You can try to add the insert statement before the failing test case. Or else remove that userRepository.deleteAll(); statement from the destroyAll() method to avoid deleting all the entries after each test case completion. Refer to the behaviour of the @AfterEach and JUnit Test case Execution sequence and decide your approach to avoid this problem.

Reference:

https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/AfterEach.html

https://www.baeldung.com/junit-5-test-order

CodePudding user response:

Because you hava an autoincremented id, you get new id's for every testcase.

You have two possiblites to get your test cases work.

First: Annotated the initUseCase with @BeforeAll, so that you insert the data only once.

@BeforeAll
static void initUseCase() {
    User user1 = new User(null, "First N1", "Last N1", "[email protected]", "password", UserRole.USER,
            null,
            false, true);
    User user2 = new User(null, "First N2", "Last N2", "[email protected]", "password", UserRole.USER,
            null,
            false, true);
    User user3 = new User(null, "First N3", "Last N3", "[email protected]", "password", UserRole.USER,
            null,
            false, true);

    List<User> users = Arrays.asList(user1, user2, user3);
    userRepository.saveAllAndFlush(users);
}

Second: you can store the saved entity in variable and against them:

List<User> entities;

@BeforeEach
void initUseCase() {
    User user1 = new User(null, "First N1", "Last N1", "[email protected]", "password", UserRole.USER,
            null,
            false, true);
    User user2 = new User(null, "First N2", "Last N2", "[email protected]", "password", UserRole.USER,
            null,
            false, true);
    User user3 = new User(null, "First N3", "Last N3", "[email protected]", "password", UserRole.USER,
            null,
            false, true);

    List<User> users = Arrays.asList(user1, user2, user3);
    entities = userRepository.saveAllAndFlush(users);
}

@Test
@Transactional
void testFindById_Success() {
    assertTrue(userRepository.findById(entities.get(0)).isPresent());
    assertEquals("First N1", userRepository.findById(1L).get().getFirstName());
}

CodePudding user response:

The problem was that it was generating new Ids each time @BeforeAll was triggered. Once I changed the Id in findById to 4 it found a match.

A way to get over this was adding the following annotation:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
  • Related