Search code examples
spring-bootmockingintegration-testing

How to create tests in a Spring boot application without the main class (using Mockito)


I have a library, the project is written in springbot, but there is no need to use main class here

interface Helper{
  String transform(int index);
}
class HelperImpl implements Helper{

private final Convert convert();

  public Helper(Convert convert){

  this.convert = convert.
 }

 public String transform(int index){

   int res = convert.print(index);

   return  String.valueOf(res);
 }
}

interface Convert {
int print(int value);

}
class ConvertImpl implements Convert{

public int print(int value){
    return 1;
  }

}
@DisplayName("Message ")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Slf4j
class Test {

    @Autowired
    Helper helper;

    @Autowired
    Convert convert;


    @BeforeAll
    void init() {
      }

    @Test
    void testRun() {
      
     String result = helper.transform(1);

  }
}

How can I write an integration test, during the raising of which an inject would be automatically made and I would only have to call methods through the received instances, pass values, get the result and check it. This is the same inject and it does not work.


Solution

  • The @Autowired annotation is a Spring annotation, hence cannot be used without a Spring context being loaded.
    There are three usual solutions to provide the instances of the classes required by the classes under test :

    Manual instantiations

    You don't use Spring, and instantiate the dependencies using the new keyword, or using Mockito for the dependencies that have to be mocked. Constructor injection is preferred to field injection, as it will allow you to easily bypass Spring in your unit tests.

    Pros : Faster to run. Easier to configure
    Cons : It can sometimes be complex to manually provide all the required dependencies. If your code heavily relies on Spring features, then, in some situations, it can be a bit more complex to use this solution.

    Using @SpringBootTest

    You want to rely on the same Spring configuration that you will use at runtime, then you should use the Springboot solution : the @SpringBootTest annotation, and the @MockBean annotation for the dependencies that you want to mock.
    Pros : Facilitate the dependency injection. Spring features can be used in the tests. It's easy to mock the dependencies with the @MockBean annotation.
    Cons : The Spring application context is required and can be slow to initialize in large projects. Note that it will be reused between tests if it doesn't have to change.

    Using SpringExtension

    You'll have to provide a Spring configuration that will define the beans that you want to autowire.

    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = { SpringTestConfiguration.class })
    public class MyTest { 
      
      @Autowired
      Helper helper;
    
      ...
    }
    
    @Configuration
    public class SpringTestConfiguration {
    
      @Bean
      public Helper helper() { return new Helper(); }
      }
    }