Search code examples
springspring-bootjunitmockitojunit-jupiter

Spring Starter Test - JUnit SpringBoot


Hello im new in testing and I first time trying to test a JpaRepository which interact with postgres in reality but in test it interacte with H2 Db i ve installed H2 dependencie and the software aswell but i still have a problem when using the repository on my test btw the dependencie is mention in scope test just to clarify more, any whenever i run this test below i got this error:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field initService in com.project.socializer.SocializerApplication required a bean of type 'com.project.socializer.runner.InitService' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'com.project.socializer.runner.InitService' in your configuration.

`***************************
APPLICATION FAILED TO START
***************************

Description:

Field initService in com.project.socializer.SocializerApplication required a bean of type 'com.project.socializer.runner.InitService' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'com.project.socializer.runner.InitService' in your configuration.`

here is my code :

package com.project.socializer.user.repository;

import com.project.socializer.SocializerApplication;
import com.project.socializer.user.entity.Roles;
import com.project.socializer.user.entity.UserEntity;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
@DataJpaTest
class UserRepositoryTest {

    @Autowired
    UserRepository userRepository;


    @BeforeEach
    void setUp() {
        userRepository.save(new UserEntity("Jhon","Doe","jhon.doe@gmail.com","test1234","1999-12-19",new Roles("USER")));
    }

    @AfterEach
    void afterEach() {
        userRepository.deleteAll();
    }

    @Test
    void findByEmail() {
        Optional<UserEntity> userTest = userRepository.findByEmail("jhon.doe@gmail.com");
        assertTrue(userTest.isPresent(),"User Exist");
    }
}

i tried many thing but sems nothing to work i dont know whats the problem and i hope for a fix from you.


Solution

  • I just had to set this up myself and I can relate to the frustration.

    If you are using an in-memory database to run an integration test you have to remember that there is a lot more going on behind the scenes to load your updated PersistenceUnit (where your database details are defined) than meets the eye. What that error message is telling you is that somewhere in the background, in order for one of your test dependencies to be initialized, it has a transitive dependency on this InitService class. So it is starting up the Spring container, discovers it needs one of these InitService instances, and then finds that it doesn't exist (since we never initialized it). To correct this, we'll need to load your original production SpringBoot configuration, with all of its Beans and settings. (Incidentally, this is extremely expensive processing-wise which is why a lot of developers recommend you just mock your DAO classes rather than hit a real database for the tests).

    Now assuming you still want to test your DAO layer without mocking it (I know I did), to initialize a test run using your production starting point, you'll want to use the @SpringBootTest annotation within your test class. What this does is tell your project that you want to initialize using your @SpringBootApplication configuration along with your test.

    This can be confirmed as expected usage per this line in the @DataJPATest Javadoc:

    If you are looking to load your full application configuration, but use an embedded database, you should consider @SpringBootTest combined with @AutoConfigureTestDatabase rather than this annotation.

    Don't quote me on this, but I believe that if you use a copy of applications.properties within your src/test/resources folder to define your test PersistentUnit, you do not need to use this @AutoConfigureTestDatabase annotation. I didn't require it but then again, I stuck to the JPA interfaces rather than implement the Spring Data so your mileage may vary.

    As a final mention, since this is going to reload your entire application in order to run just one test, processing can bubble out of control quickly. As such, I would recommend using profiles (@Profile and @ActiveProfiles) and configuration classes (@Configuration and @TestConfiguration) to partition your @Bean definitions so that you can better control what gets loaded and when. Partitioning your configurations also has the added benefit of letting you call different component and entity scan commands depending on the profile, which can help better organize your project.

    Hope that helps!