Search code examples
springdatabasespring-securitymockitospring-boot-test

Not able to save data in H2 Database using SpringBootTest and Spring JPA Repository


I am using @SpringBootTest to test SpringSecurity basic authentication.When I test it,the h2 database does not save the data.I do not see the insert statement in the console,which I apparently see when I am running my actual SpringBoot Application and inserting the data from frontend. Please help.

Below is my test:

        @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
        @ContextConfiguration(classes=ConnectionsAppApplication.class)
        @Transactional
        public class AuthenticationTest {

            @Autowired
            private WebApplicationContext context;

            private MockMvc mockMvc;

            @Mock
            CustDetailsRepository custRepository;

            @Mock
            BCryptPasswordEncoder encrypt;

            @InjectMocks
            CustomerServiceImpl customerServiceImpl;



           @BeforeEach
           public void setup() {

             MockitoAnnotations.initMocks(this);
             mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(springSecurity())
                .build();
           }


          @Test
          void testAuthentication() {

              CustomerDetails customer = new CustomerDetails();
              customer.setEmailid("abc.com");
              customer.setPassword("abc@123456");
              customerServiceImpl.saveUser(customer);
           try {
               this.mockMvc.perform(get("/api/login")
               .with(httpBasic("abc.com","abc@123456")))
               .andDo(print())
               .andExpect(status().isOk())
               .andReturn();
           } catch (Exception e) {
                e.printStackTrace();
            }
         }

       }

saveUser method in CustomerServiceImpl class:

        public void saveUser(CustomerDetails customerDetails) {
          customerDetails.setPassword(bCryptPasswordEncoder.encode(customerDetails.getPassword()));
          custDetailsRepository.save(customerDetails);
         }

Solution

  • You have 2 options to implement this test:

    Option 1: use real h2

    @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
    @ContextConfiguration(classes=ConnectionsAppApplication.class)
    @Transactional
    public class AuthenticationTest {
    
        @Autowired
        private WebApplicationContext context;
    
        private MockMvc mockMvc;
    
        @Autowired
        CustomerServiceImpl customerServiceImpl;
    
        @BeforeEach
        public void setup() {
    
            mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(springSecurity())
                .build();
        }
    
    
        @Test
        void testAuthentication() {
    
            CustomerDetails customer = new CustomerDetails();
            customer.setEmailid("abc.com");
            customer.setPassword("abc@123456");
            customerServiceImpl.saveUser(customer);
            try {
                 this.mockMvc.perform(get("/api/login")
                     .with(httpBasic("abc.com","abc@123456")))
                     .andDo(print())
                     .andExpect(status().isOk())
                     .andReturn();
             } catch (Exception e) {
                 e.printStackTrace();
             }
        }
    }
    

    Option 2: Mock your service / repository

    @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
    @ContextConfiguration(classes=ConnectionsAppApplication.class)
    @Transactional
    public class AuthenticationTest {
    
        @Autowired
        private WebApplicationContext context;
    
        private MockMvc mockMvc;
    
        @MockBean
        CustomerServiceImpl customerServiceImpl;
    
        @BeforeEach
        public void setup() {
            mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(springSecurity())
                .build();
        }
    
    
        @Test
        void testAuthentication() {
            // set expectations on CustomerServiceImpl
            CustomerDetails customer = new CustomerDetails();
            customer.setEmailid("abc.com");
            customer.setPassword("abc@123456");
            // mock the method you use to fetch the customer
            when(customerServiceImpl.getUser("abc.com").thenReturn(customer);
            try {
                this.mockMvc.perform(get("/api/login")
                    .with(httpBasic("abc.com","abc@123456")))
                    .andDo(print())
                    .andExpect(status().isOk())
                    .andReturn();
               } catch (Exception e) {
                    e.printStackTrace();
               }
          }
    }
    

    Note that you also can use @WebMvcTest to test only the web slice of your app (meaning no other beans will be instantiated, for example all sercies you depend in the controller must be delivered by @MockBean)