【问题标题】:Unit testing a REST API in Java and Spring在 Java 和 Spring 中对 REST API 进行单元测试
【发布时间】:2018-03-19 02:11:30
【问题描述】:

我有一个简单的 Java Spring REST API 应用程序,但我不知道如何对其进行单元测试。我已经阅读了 JUnit 和 Mockito 的文档,但我无法弄清楚。

这是StudentController类中的post方法

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

这里是 StudentService 类中的 insertStudent 方法

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

我使用 MySQL 作为数据库。我也应该使用数据库进行单元测试吗?我的意思是我不想要任何集成测试。我只想要单元测试。我在 Node.js 中使用 supertest,它照顾到了所有人,我也可以用 JUnit 或 Mockito 来做吗?

【问题讨论】:

  • 控制器的 mockist 单元测试将模拟服务并确保调用正确的方法,您当然可以使用 JUnit+Mockito 来做到这一点。那么就不需要数据库了,因为真正的服务根本没有被使用。
  • @jonrsharpe 你能给我一个链接,告诉我如何做到这一点吗?
  • 已经有很多例子了,我建议研究一下。参见例如stackoverflow.com/q/10906945/3001761

标签: java spring rest unit-testing junit


【解决方案1】:

如果您想进行单元测试,则不必连接到数据库。连接到数据库和其他外部服务将被视为集成测试。因此,在测试您的 StudentService 类时,对数据库的请求将被模拟出来。

值得一提的第二点是,您将分别测试控制器类和服务类,但在您的情况下,这些测试看起来非常相似。

以下是您可以测试控制器的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);
    }

由于你控制器的insertStudent方法没有if语句,只有一个分支,所以基本上只需要执行一个测试,基本上是控制器调用服务。

另一种测试方法是使用 Springs MockMvcMockMvc 的好处在于它可以让您测试 HTTP 请求。例如,在这种情况下,您需要测试控制器的 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 有其他很酷的方法你应该探索。

【讨论】:

    【解决方案2】:

    我有一个简单的 Java Spring REST API 应用程序

    你真的应该早点开始考虑单元测试。最好的方法是生产代码实现(新)行为(TDD)之前。

    这是StudentController类中的post方法

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

    这段代码太简单了,不会失败。 为这样的代码编写单元测试是浪费时间。像这样的代码通过 applicationmodule tests

    进行测试

    一旦有一些决定要做(例如:根据输入参数对其他对象进行额外调用),我就会开始为此代码编写单元测试。

    这里的重点是单元测试不测试代码 - 单元测试验证期望的行为(在您的要求中表达)。所以是的:不测试这种方法会降低报告的覆盖率。但是任何覆盖率工具计算的数字都没有需求覆盖率重要,没有任何工具可以计算,并且只能通过 TDD 来保证。

    【讨论】:

    • 我不同意“为这样的代码编写单元测试是时间的‘腰’”。 OP 正在寻找一种对其进行测试的方法,并且有一些方法(就像其他人建议的那样)来做到这一点。
    【解决方案3】:

    您想模拟 studentService 并进行单元测试,以验证当 API 的方法 insertStudent(Student) 被调用时,恰好有一个对服务的 insertStudent(Student) 的调用具有相同的 Student 实例。

    然后为不同的场景创建单元测试,即处理nulls 等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-09
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 2021-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多