简体   繁体   中英

Junit 5 with test application.properties

I am learning Junit 5 and test cases. I am using spring boot version '2.2.6.RELEASE and JUnit 5, in my application, I have a method that processes based on the boolean flag from property file.

\src\main\resources\application.properties

#data base connection properties
spring.app.datasource.url=jdbc:mysql://localhost:3306/student_db
spring.app.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.app.datasource.username=root
spring.datasource.password=root
spring.app.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

#additional properties
spring.property.name=shrikant
spring.property.enable=false

database connection properties are used to create the database connection

Datasource.java

@Value("${spring.app.datasource.url}")
private String url;
@Value("${spring.app.datasource.driver-class-name}")
private String className;
@Value("${spring.app.datasource.username}")
private String userName;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.app.jpa.properties.hibernate.dialect}")
private String dialect;

controller class

@RestController
public class Controller {
    @Value("${spring.property.name}")
    private String name;
    @Value("${spring.property.enable}")
    private boolean status;

    public void validateObject(String surName) {
        if (status) {                              # if this flag is true then only process
            System.out.println("name= " + name);
            System.out.println("surName= " + surName);
        }
    }

ControllerTest.java

@SpringBootTest
class ControllerTest {
    @Autowired
    private Controller controller;
    @Test
    void show() {
        controller.validateObject("sharma");
    }

by default the flag is false, so every time test case runs it never processes the object. so I tried to create aplication.properties in the test folder

\src\test\resources\application.properties

spring.property.name=vishal
spring.property.enable=true

but now it's giving me an error that

Could not resolve placeholder 'spring.app.datasource.url'

but I don't want to provide DB connection URL, I am not connecting to the database while testing.

Q1 - how to change the value of properties file for test case only.

Q2 - is it mandatory to provide all the keys of \src\main\resources\application.properties is \src\test\resources\application.properties?

I am new in test case, so little explained answers would be welcomed.

Update:- I found that

@SpringBootTest
@TestPropertySource(properties = {"spring.property.name=vishal", " spring.property.status=true"})
class ControllerTest {

will solve the issue temporarily, by providing keys along with values, but I have a lot of keys, which cannot be provided in such a way.

If you use @SpringBootTest then your test will load the whole Spring context. This means it will create all your beans and try to wire them together. If you inject property values to your beans, you have to specify them all for such tests as otherwise, you won't be able to boot the application.

What might help you in such a situation is to use test annotations like @WebMvcTest or @DataJpaTest to focus on testing just slices of your application. Using @WebMvcTest you'll get an application context just containing controllers and everything related to your web layer. Other beans (like service classes) can be mocked with @MockedBean .

Next, for testing business logic in service classes try not to use @SpringBootTest and rather rely on plain JUnit 5 and Mockito to verify your code.

You still might want to have some integration tests that use @SpringBootTest to make sure everything is working together. In such case, you can hard code any static property inside application.properties in src/test/resources/ or using the annotation like you already did: @TestPropertySource(properties = {"spring.property.name=vishal", " spring.property.status=true"}) .

When it comes to providing a database, you can either configure an embedded database (which I would try to avoid) or use the same database as in production. Testcontainers helps you a lot when it comes to providing external infrastructure for your tests like a database.

An example setup with Spring Boot >= 2.2.6 and JUnit might look like the following:

@Testcontainers
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class ApplicationIT {
 
  @Container
  public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer()
    .withPassword("password")
    .withUsername("username");
 
  @DynamicPropertySource
  static void postgresqlProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
    registry.add("spring.datasource.password", postgreSQLContainer::getPassword);
    registry.add("spring.datasource.username", postgreSQLContainer::getUsername);
  }
 
  @Test
  public void contextLoads() {
  }
 
}

For Junit5, annotate your test class with path to application.properties in your src/main/resources :

@ExtendWith(SpringExtension.class)
@TestPropertySource("classpath:application.properties")
public class MyTest {
    @Value("${property.name}")
    private int myProperty;
    tests...
}

property gets loaded

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM