当前位置: 首页 > 知识库问答 >
问题:

我想为Spring Boot服务方法编写一个mockito测试用例

长孙绍辉
2023-03-14

这就是服务方法。

    @Override
    public void removeStudentByID(Long studentId) throws StudentExistsException {
        boolean exists = studentRepo.existsById(studentId);
        if (!exists) {
            throw new StudentExistsException("Student doesn't exist");
        }
        studentRepo.deleteById(studentId);
    }

下面是我为它编写的测试用例。

@Test
    public void removeStudentByIdTest() throws StudentExistsException {
        Student student = new Student(1, "Drake", "drake@gmail.com");
        when(studentRepo.save(student)).thenReturn(student);
        studentService.removeStudentByID(student.getId());
        assertEquals(false, studentRepo.existsById(student.getId()));
    }

它没有运行。。。但是下面的代码是有效的。

    public void removeStudent(String email) {
        Student student = studentRepo.findByEmail(email);
        studentRepo.delete(student);
    }
@Test
    public void removeStudentTest() throws StudentExistsException {
        Student student = new Student(3, "Ben", "ben@gmail.com");
        studentRepo.save(student);
        studentService.removeStudent(student.getEmail());
        assertEquals(false, studentRepo.existsById(student.getId()));
    }

所以,作为一个noob,我有点困惑如何使它在第一个工作。或者两者都有问题。

共有2个答案

高修筠
2023-03-14

这就是我做的,让我知道它是好的。:)

@Test
    public void removeStudentByIdTest() throws StudentExistsException {
        Student student = new Student(1, "Drake", "drake@gmail.com");
        when(studentRepo.existsById(student.getId())).thenReturn(true);
        studentService.removeStudentByID(student.getId());
        verify(studentRepo).deleteById((long) 1);
    }
左丘源
2023-03-14

要测试此代码,请执行以下操作:

@Service
public class StudentService { 
  @Override
  public void removeStudentByID(Long studentId) throws StudentExistsException 
    boolean exists = studentRepo.existsById(studentId);
    if (!exists) {
        throw new StudentExistsException("Student doesn't exist");
    }
    studentRepo.deleteById(studentId);
  }
}

我们可以这样模拟/"单元测试":

package com.example.demo;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class StudenServiceTests { // we only test StudentService, since we (sort of) trust studentRepository (tested it elsewehere/how)

  @Mock // A Mock! (alternatively @MockBean)
  private StudentRepository studentRepoMock;
  @InjectMocks // A real service (with mocks injected;)!!! (alternatively @Autowired/...)
  private StudentService testee; // this guy we want to test (to the bone!)

  @Test // ..the "good case"
  void removeStudentByIdExists() throws StudentExistsException {
    // Given:
    // we don't even need a student, only his id
    // instruct mock for the "first interaction" (see testee code):
    when(studentRepoMock.existsById(1L)).thenReturn(true);
    // instruct mock for "second interaction" (see testee code):
    doNothing().when(studentRepoMock).deleteById(1L); // we could also use ...delete(any(Long.class))  or ..anyLong();

    // When: (do it!)
    testee.removeStudentByID(1L);

    // Then: Verify (interactions, with as exact as possible parameters ..Mockito.any***)
    verify(studentRepoMock).existsById(1L); //.times(n) ...when you had a list ;)
    verify(studentRepoMock).deleteById(1L);
  }

  @Test // .. the "bad (but correct) case"/exception
  void removeStudentByIdNotExists() throws StudentExistsException {
    // Given:
    when(studentRepoMock.existsById(1L)).thenReturn(false);

    // When:
    StudentExistsException thrown = assertThrows(
            StudentExistsException.class,
            () -> testee.removeStudentByID(1L),
            "Expected testee.removeStudentByID to throw, but it didn't");
    // Then:
    assertNotNull(thrown);
    assertTrue(thrown.getMessage().contains("Student doesn't exist"));
  }
}

... 使用mvn测试运行

通过这两个测试用例,我们实现了100%的测试(

但不要将其与“集成测试”(我们使用真实的回购/数据库)混淆,然后我们可以使用:

  • JDBC测试支持
  • 测试注释(@Commit、@Rollback、@Sql*
  • JdbcTemplate

“默认”(假设为空)数据库上的示例,带有准备(和@Rollback):

package com.example.demo;

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

@SpringBootTest
class StudentServiceIT { // .. here we try to test "all of our application" (as good as possible ..to the bone)

  @Autowired //! real "bean", no mock... this is only auxilary for this test, we could use some other method to prepare & verify
  private StudentRepository studentRepository;
  @Autowired //!! "real service"
  private StudentService studentService;

  @Test
  @Rollback // actually our test is "self-cleaning"...when no exceptions ;)
  void removeStudentByIdExists() throws StudentExistsException {
    // Given:
    Student student = new Student(1L, "Drake", "drake@gmail.com");
    studentRepository.save(student);

    // When:
    studentService.removeStudentByID(1L);

    // Then:
    assertFalse(studentRepository.findById(1L).isPresent());
  }

  @Test
  @Rollback // in any case (if assumptions were wrong;)
  void removeStudentByIdNotExists() throws StudentExistsException {
    // Given:
    // nothing, we assume "empty db"

    // When:
    StudentExistsException thrown = assertThrows(
            StudentExistsException.class,
            () -> studentService.removeStudentByID(1L),
            "Expected testee.removeStudentByID to throw, but it didn't");
    // Then:
    assertNotNull(thrown);
    assertTrue(thrown.getMessage().contains("Student doesn't exist"));
  }
}

(运行时使用:mvn故障保护:集成测试

感谢/参考文献:

  • JUnit5:如何断言抛出异常
  • Mockito测试无效方法引发异常
  • @Mock和@injectmock之间的区别

完成Sample@github

 类似资料:
  • 我在java中使用mockito编写单元测试。 这就是我要测试的声明。 电影是电影名称的集合,是识别电影的关键。 我嘲笑了守望者班 Mockito.when(watcher.watch(Matchers.any(Set.class))) “thenReturn”中包括什么??

  • 我不熟悉单元测试。参考google之后,我创建了一个测试类来测试我的控制器,如下所示: 我有以下控制器和服务类: 当我调试单元测试时,控制器中的p对象为null。我的状态是200,但不是预期的JSON响应 我错过了什么?

  • 我有下面的类,我测试了method1,并模拟了method2和method3。我只测试这样的用例:*如果method2调用是OK,那么==>OK*如果method2抛出NotFoundException,method3返回OK==>OK*如果method2抛出NotFoundException,method3抛出ServiceException==>ServiceException确实抛出了 为了

  • } ---编辑1--更改 根据注释,断言是失败的。

  • 我必须为一个调用API然后处理响应的类编写测试。类有两个公共函数和一个私有函数。第一个公共方法获取ID列表。在循环中为每个ID调用第二个公共方法,以获取与ID关联的详细信息。私有方法是在第二个公共方法内部调用的,因为获取基于id的详细信息的调用是异步进行的。 我是JUnits的新手,虽然我知道我不应该测试API调用,只是测试我的函数,但我仍然不明白单元测试应该断言什么。

  • 如何为RestController,Service和DAO层编写JUnit测试用例? 我试过 如何验证rest控制器和其他层中的CRUD方法?