Patrick C.
Patrick C.

Reputation: 1429

Spring Boot console application causes JUnit test case to wait

I have Spring Boot console application which accepts user input. In the same application, there are service to perform some logic.

On running the service's JUnit test case directly, I am observing a behavior where the console application stays in the state of accepting user input, and thus not entering the JUnit tests.

Usually there is no issue becasue for a normal Spring Boot application, there is nothing to run on start up. But for this console application setup, it awaits user input.

May I know if there is any way that can make the test cases run while not triggering the console application? Thank you very much.

Observation: The console application is triggered on JUnit test case run, test case is not entered

enter image description here

Main application

import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ToyRobotApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(ToyRobotApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        // Instruct user to perform input
        System.out.println("Welcome to toy robot application!");
        System.out.println("Below are the possible operations:");
        System.out.println("PLACE <x-coordinate> <y-coordinate> <facing>");
        System.out.println("MOVE");
        System.out.println("LEFT");
        System.out.println("RIGHT");
        System.out.println("REPORT");

        while (true) {
            System.out.println("Please enter your command:");

            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String usrInput = br.readLine();
            //...

        }
    }
}

Test case

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.somecompany.model.Facing;
import com.somecompany.model.Location;
import com.somecompany.model.Robot;
import com.somecompany.service.ToyRobotService;

@SpringBootTest
public class ToyRobotReportTest {

    @Autowired
    private Robot robot;

    @Autowired
    private ToyRobotService toyRobotService;

    @Test
    public void shouldBeAbleToReportLocation() {
        Location location = new Location();
        location.setXCor("1");
        location.setYCor("2");
        location.setFacing(Facing.NORTH);

        robot.setLocation(location);

        // Actual result
        String result = toyRobotService.report();

        // Assertion
        assertEquals("1,2,NORTH", result);
    }
}

Note: Other sources omitted

Upvotes: 0

Views: 1011

Answers (1)

Patrick C.
Patrick C.

Reputation: 1429

I got the setup working after some research. To get this to work, the JUnit test class should not be annotated with the usual @SpringBootTest annotation.

When the class is annotated with @SpringBootTest, it will start up the application's context (i.e. start the application). In most usual test scenarios, this should be fine if there is no waiting of user input.

In our case, we want the Spring Boot annotations (e.g. @Autowired) to be recognized, but do not want the application itself to be started up.

We can use the following in JUnit:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ToyRobotApplication.class, initializers = ConfigDataApplicationContextInitializer.class)
public class ToyRobotPlaceTest {
    ...
}

This will regonize spring annotations, but will not start the application context.

Upvotes: 1

Related Questions