【问题标题】:What is better way to write Unit test in Spring Boot using Junit?使用 Junit 在 Spring Boot 中编写单元测试的更好方法是什么?
【发布时间】:2020-10-02 04:27:46
【问题描述】:

我们有多个控制器的项目,并使用 Mockito 和 Junit 来编写 UNIT 测试。 当我们添加新功能时,我们的单元测试数量每天都在增长。

我为以下课程编写了如下测试。

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());

  }

}

编写 JUNIT 的更好方法是什么?像 TestDataController2.java 中所示使用 @Mock 服务更好,还是我们可以使用 @InjectMocks 服务和存储库来覆盖所有测试用例,如 TestDataController.java 所示?

【问题讨论】:

  • 你不需要初始化像Service service = new Service()这样的属性。另外,尽量避免反射,可能你想使用@BeforeEach,因为@BeforeAll 方法应该是static。所以,第二个更好,不过,不要用new 初始化属性,因为你已经注释了它们。
  • 我删除了新服务的初始化,但是当我删除下面的行时,ReflectionTestUtils.setField(controller, "service", service);在调用服务方法的控制器方法中获取 Nullpointer。

标签: java spring-boot unit-testing junit mockito


【解决方案1】:

我认为在使用@Mock@InjectMocks 时应该避免手动初始化属性;反射也不是一种健康的初始化方式。

您应该始终通过构造函数进行依赖注入,以避免以后通过反射进行注入,这会使您的类在一段时间内处于不一致的状态(依赖项将为空)。

所以,这就是你可以做的。

简单的控制器和服务。注意构造函数注入。

@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";
    }

}

现在Controller的测试类就是这个了。无反射无手动初始化。

@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());
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-26
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-19
    • 1970-01-01
    相关资源
    最近更新 更多