简体   繁体   English

在Java和Spring中对REST API进行单元测试

[英]Unit testing a REST API in Java and Spring

I have a simple Java Spring REST API application and i don't know how can i unit test it. 我有一个简单的Java Spring REST API应用程序,我不知道如何进行单元测试。 I have read the documentations of JUnit and Mockito, but i couldn't figure it out. 我已经阅读了JUnit和Mockito的文档,但无法弄清楚。

Here is the post method in the StudentController class 这是StudentController类中的post方法

@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
    public void insertStudent(@RequestBody Student student){
        studentService.insertStudent(student);
    }

And here is the insertStudent method in the StudentService class 这是StudentService类中的insertStudent方法

public void insertStudent(Student student) {
        studentDao.insertStudent(student);
    }

I use MySQL for database. 我将MySQL用于数据库。 Should i use database too for unit test? 我也应该将数据库用于单元测试吗? I mean i don't want any integration test. 我的意思是我不需要任何集成测试。 I want only unit test. 我只需要单元测试。 I use supertest in Node.js and it takes care for all, can i do that with JUnit or Mockito too? 我在Node.js中使用超级测试,它可以照顾所有人,我也可以使用JUnit或Mockito做到这一点吗?

If you want to do unit testing then you would not have to connect to the DB. 如果要进行单元测试,则不必连接到数据库。 Connecting to DB's and other external services would be considered integration testing. 连接数据库和其他外部服务将被视为集成测试。 So the request to the DB would be mocked out when testing your StudentService class. 因此,在测试StudentService类时,将嘲笑对数据库的请求。

Second point worth mentioning is that you would test your controller class and you service class separately, but in your case those tests would look very similar. 值得一提的第二点是,您将分别测试控制器类和服务类,但是在您的情况下,这些测试看起来非常相似。

Below is one way you can test your controller's insertStrundent method. 下面是测试控制器的insertStrundent方法的一种方法。

@RunWith(MockitoJUnitRunner.class)
public class TestStudentContoller {

    @Mock
    StundentService mockStudentService;
    @InjectMocks
    StudentController studentController = new StudentController();

    @Test
    public void testInsertStudent(){

        Student student = new Student();

        studentContoller.insertStudent(student);

        verify(studentService, times(1)).insertStudent(student);
    }

Since you controller's insertStudent method has no if statements and only one branch, there is basically only one test that needs to be performed, basically does the controller call the service. 由于控制器的insertStudent方法没有if语句,只有一个分支,因此基本上只需要执行一个测试,因此控制器会调用服务。

Another way it can be tested is with Springs MockMvc . 可以测试它的另一种方法是使用Springs MockMvc The good thing about the MockMvc is that it lets you test the HTTP request. 关于MockMvc是,它可以让您测试HTTP请求。 For example in this case you would want to test that your controller's insertStudent method will properly respond to HTTP POST requests with a JSON Student. 例如,在这种情况下,您将要测试控制器的insertStudent方法是否可以使用JSON Student正确响应HTTP POST请求。

@RunWith(MockitoJUnitRunner.class)
public class TestStudentContoller {

    @Mock
    StundentService mockStudentService;
    @InjectMocks
    StudentController studentController = new StudentController();

    MockMvc mockMvc;

    @Before
    public void setup(){
        mockMvc = MockMvcBuilders.standAloneSetup(studentController).build();
    }

    @Test
    public void testInsertStudent(){

        Student student = new Student();

        studentContoller.insertStudent(student);

        mockMvc.perform(post("path/to/insert/student")
            .accept(MediaType.APPLICATION_JSON)
            .andExpect(status().isOk())
            .andExpect(content().string("{}"));//put json student in here

        verify(studentService, times(1)).insertStudent(student);
    }

MockMvc has other cool methods you should explore. MockMvc还有其他MockMvc方法,您应该探索。

I have a simple Java Spring REST API application 我有一个简单的Java Spring REST API应用程序

You should really start earlier to think about unittests. 您应该更早地开始考虑单元测试。 The best way to do them is before the production code implements the (new) behavior ( TDD ). 最好的方法是生产代码实现(新)行为( TDD )之前。

Here is the post method in the StudentController class 这是StudentController类中的post方法

 @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) public void insertStudent(@RequestBody Student student){ studentService.insertStudent(student); } 

This code is too simple to fail . 这段代码太简单了,以至于无法失败 Writing unittests for such code is a waist of time. 为此类代码编写单元测试是很长的时间。 Code like this is tested via application or module tests 这样的代码通过应用程序模块测试进行了测试

I would start writing unittests for this code as soon as there is some decision to make (eg: additional calls to other objects depending on the input parameters). 一旦做出决定 (例如:根据输入参数对其他对象的额外调用),我将开始为该代码编写单元测试。

The point here is that unittests do not test code - unittests verify desired behavior (which is expressed in your requirements). 这里的重点是单元测试不测试代码 -单元测试验证所需的行为 (在您的需求中表示)。 So yes: not testing this method reduces the coverage in your reports. 所以可以:不测试此方法会减少报告的覆盖范围。 But the number any coverage tool calculates is less important than the requirement coverage which no tool can calculate and which you can only guarantee by doing TDD. 但是,任何覆盖率工具计算的数量都比没有工具可以计算并且只能通过执行TDD才能保证的需求覆盖率重要。

You want to mock studentService and have a unit test that verify that when the method insertStudent(Student) of the API is called then there is exactly one call to the service's insertStudent(Student) with the same Student instance. 您要模拟studentService并进行单元测试,以验证当调用API的方法insertStudent(Student) ,对于具有相同Student实例的服务的insertStudent(Student)确实存在一个调用。

Then create unit tests for different scenario, ie handling null s etc.. 然后针对不同的场景创建单元测试,即处理null等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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