Search code examples
mysqlspring-bootunit-testingintegration-testing

Intgration Test in springboot pass when test at each method but fail when running class


It seems pass when a run the test individually but fine when fair when running the class .I have tried to use @Before and @After annotatoon.And only the Dirtiescontext most fit my case.My question is any alternative for dirtiescontext(too slow) or any method can suit my case?

My test code:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@AutoConfigureMockMvc
class UserCoreControllerTest  {


    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserCoreService userCoreService;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private MockMvc mockMvc;
/*
   *//* @BeforeTestMethod
    public void setUp(){
        System.out.println("begin");
        userRepository.save(mockUser());
    }
    @AfterTestMethod
    public void tearOff(){
        System.out.println("end");
        userRepository.deleteById(1);
    }
*/
    private User mockUser(){

        User user= new User(0,"admin","admin",null,null,"yl","sd"
                ,"434","dsf",null,4,2,new ArrayList<>());
        user.getApplications().add(mockJobOrder("job1title","b"));
        user.getApplications().add(mockJobOrder("job2title","d"));
        return user;
    }

    private JobOrder mockJobOrder(String title,String des){
        return new JobOrder(0,1,title,des,null,null,0,2,false,0,null);

    }





    @Test
    void getProfile() throws Exception {
        userRepository.save(mockUser());
         mockMvc.perform(get("/UserJob/getProfile/{id}", 1)
                        .accept(MediaType.APPLICATION_JSON_VALUE)
                )

                .andExpect(status().isOk())
                 .andExpect(jsonPath("$.username")
                         .value("admin"))

                .andDo(print());


    }
    @Test
    void getUserByName() throws Exception {
        userRepository.save(mockUser());
        mockMvc.perform(get("/UserJob/get/Byusername/{username}", "admin")
                        .accept(MediaType.APPLICATION_JSON_VALUE)
                )
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.password").value("admin"));
        //if cant found user
        MvcResult whatever = mockMvc.perform(get("/UserJob/get/Byusername/{username}", "whatever")
                        .accept(MediaType.APPLICATION_JSON_VALUE)
                )
                .andExpect(status().isOk())
                .andReturn();

        Assertions.assertEquals("",whatever.getResponse().getContentAsString());

    }


    @Test
    void updateUser() throws Exception {
        userRepository.save(mockUser());
        User updated=new User(1,"alex","admin",null,null,"yl","sd"
                ,"434","dsf",null,4,2,null);
        String request=objectMapper.writeValueAsString(updated);

        MvcResult mvcResult=mockMvc.perform(MockMvcRequestBuilders.put("/UserJob/updateuser")
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON_VALUE)
                        .content(request)
                )
                .andExpect(status().isOk())
                .andDo(print())
                .andReturn();

        Assertions.assertEquals("Successful update",mvcResult.getResponse().getContentAsString());

        mockMvc.perform(get("/UserJob/getProfile/{id}", 1)
                        .accept(MediaType.APPLICATION_JSON_VALUE)
                )

                .andExpect(status().isOk())
                .andExpect(jsonPath("$.username")
                        .value("alex"))

                .andDo(print());

    }


    @Test
    void showApplicationshistory() throws Exception {

        userRepository.save(mockUser());


        mockMvc.perform(get("/UserJob/application/history/{id}", 1)
                        .accept(MediaType.APPLICATION_JSON_VALUE)
                )
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[0].title").value("job1title"))
                .andExpect(jsonPath("$[1].title").value("job2title"))
                .andDo(print());

    }




    @Test
    void addUser() throws Exception {
        User user=mockUser();
                user.setUsername("tom");


        String request=objectMapper.writeValueAsString(user);
        mockMvc.perform(MockMvcRequestBuilders.post("/UserJob/add/user")
                .contentType(MediaType.APPLICATION_JSON)
                .content(request)
                .accept(MediaType.APPLICATION_JSON_VALUE))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.username").value("tom"));
    }

Application properties(i test it on a real database with drop-create)

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=*
spring.datasource.password=*
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.defer-datasource-initialization=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.sql.init.mode=always

logging.level.root=INFO

Solution

  • I guess that the test are failing because of some user constraints - since you insert the user a multiple times here.

    There are multiple solutions for that.

    1. Mark your test as transactional. The transaction is automatically rollbacked for tests.
    2. Clear the tables manually after/before each test. Either by using the repository.deleteAll() or truncate the whole db with some sql statements.

    Just as a side information: You can also use testcontainers instead of having a persistente database locally. See https://www.testcontainers.org/ or even better: a wrapper library around it: https://github.com/PlaytikaOSS/testcontainers-spring-boot