简体   繁体   中英

What is better way to write Unit test in Spring Boot using Junit?

We are having project with multiple controllers and using Mockito with Junit to write UNIT tests. Our number of unit tests are growing everyday when we add new functions.

I have written the tests as below for the below classes.

DataController.java

@RestController
public class DataController {

  @Autowired
  DataService service;

  @GetMapping("/getdata")
  public ResponseEntity<String> getUserdata() {
    String data = service.getdata();
    return new ResponseEntity<>(data, HttpStatus.OK);
  }
}

DataService.java

@Service
public class DataService {

  @Autowired
  DataRepository dataRepository;

  public String getdata() {
   return dataRepository.getData();
  }

}

DataRepository.java

@Repository
public class DataRepository {

  public String getData() {
    return "Successful data";
  }

}

TestDataController.java

   @TestInstance(Lifecycle.PER_CLASS)
public class TestDataController {

  @InjectMocks
  DataController controller = new DataController();


  @InjectMocks
  DataService service = new DataService();

  @InjectMocks
  DataRepository dataRepository= new DataRepository();

  @BeforeAll
   public void setUp() {
    MockitoAnnotations.initMocks(this);
    ReflectionTestUtils.setField(controller, "service", service);
    ReflectionTestUtils.setField(service, "dataRepository", dataRepository);
  }

  @Test
  public void test1() throws Exception {
    ResponseEntity<String> actualResponse = controller.getUserdata();
    assertEquals("Successful data", actualResponse.getBody());

  }

}

TestDataController2.java

@TestInstance(Lifecycle.PER_CLASS)
public class TestDataController2 {

  @InjectMocks
  DataController controller = new DataController();


  @Mock
  DataService service;


  @BeforeAll
  public void setUp() {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void test1() throws Exception {
    Mockito.when(service.getdata()).thenReturn("Successful data");
    ResponseEntity<String> actualResponse = controller.getUserdata();
    assertEquals("Successful data", actualResponse.getBody());

  }

}

What is the better approach to write JUNIT? Is it better to use @Mock for service as shown in TestDataController2.java or we can use @InjectMocks for service and repository to cover all in one test case as shown in TestDataController.java?

I believe manual initialization of the properties should be avoided when using @Mock and @InjectMocks ; also reflection is not a healthy way of initializing either.

You should always do your dependency injections through constructor to avoid later injections through reflection which will leave your class in inconsistent state (dependencies will be null) for a while.

So, here's what you can do.

Simple Controller and Service. Notice the constructor injection.

@Controller
public class DemoController {

    private final DemoService demoService;

    public DemoController(DemoService demoService) {
        this.demoService = demoService;
    }

    public String sayHello() {
        return this.demoService.sayHello();
    }
}

@Service
public class DemoService {

    public String sayHello() {
        return "hello";
    }

}

Now the test class of Controller will be simply this. No reflection no manual initialization.

@ExtendWith(MockitoExtension.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class DemoControllerTest {

    @Mock
    private DemoService demoService;

    @InjectMocks
    private DemoController demoController;

    @Test
    void sayHello() {
        Mockito.when(demoService.sayHello()).thenReturn("mock hello");
        assertEquals("mock hello", demoController.sayHello());
    }
}

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