n层服务层中带有Spring Boot的JUnit

问题描述 投票:1回答:2

我有模特

public class Student {

    private String name;

    // getter and setter
}

我已经实现了一个REST控制器,该控制器生成一个带有随机字符作为名称的学生对象。我有一个@RestController,绑定了一个为学生对象提供服务的@Service层,并再次生成了一个生成随机字符串的@Service层。我想通过模拟控制器和服务来使用JUnit测试我的应用程序。问题是我可以模拟为学生提供服务的控制器和服务,但未模拟stringGeneratorService服务层。

我的控制器

@RestController
public class StudentServer {

    StudentService service;

    @Autowired
    public StudentServer(StudentService service) {
        this.service = service;
    }

    @GetMapping("/generate-student")
    public Student studentGenerator() {
        return service.getRandomStudent();
    }
}

服务学生对象的我的服务层

@Service("studentService")
public class StudentService {

    StringGeneratorService stringService;

    @Autowired
    public StudentService(StringGeneratorService stringService) {
        this.stringService = stringService;
    }

    public Student getRandomStudent() {
        Student student = new Student();
        student.setName(stringService.generateRandomAlphaString());
        return student;
    }   

}

和我的RandomStringGenertor服务

@Service("stringGeneratorService")
public class StringGeneratorService {

    Random random = new Random();

    public String generateRandomAlphaNumericString() {
        // returns a randomly generated string
    }
}

我的JUnit测试类如下:

@RunWith(SpringRunner.class)
@WebMvcTest(StudentServer.class)
public class RestTest {

    @Autowired
    private MockMvc mockMvc;

    @TestConfiguration
    public static class TestConfig {
      @Bean
      public StudentService studentService(final StringGeneratorService stringGeneratorService){
       return new StudentService(stringGeneratorService);
      }
      @Bean
      public StringGeneratorService stringGeneratorService(){
        return mock(StringGeneratorService.class);
      }
    }

    @Autowired
    private StudentService studentService;

    @Autowired
    public StringGeneratorService stringGeneratorService;

    @Before
    public void setUp() {
      reset(stringGeneratorService);
    }

    @After
    public void tearDown() {
      verifyNoMoreInteractions(stringGeneratorService);
    }

    @Test
    public void testGenerateStudent() throws Exception {

         mockMvc.perform(MockMvcRequestBuilders.get("/generate-student"))
          .andExpect(MockMvcResultMatchers.status().isOk())
          .andDo(print())
          .andExpect(MockMvcResultMatchers.jsonPath("$.name").isNotEmpty());

    }
}

结果是正文= {“名称”:空}

有人可以知道我在做什么错吗?

java junit mockito spring-restcontroller
2个回答
0
投票

在您的测试配置中,为StringGeneratorServicereturn mock(StringGeneratorService.class);定义了模拟,但是您没有定义方法的模拟行为。许多返回对象的方法的默认行为是返回null,您会在结果中看到它。

您需要定义方法的模拟行为,如下所示:

@Bean
public StringGeneratorService stringGeneratorService() {
    StringGeneratorService mock = mock(StringGeneratorService.class);
    // adding the missing mocked method behavior here
    when(mock.generateRandomAlphaNumericString()).thenReturn("expectedMockedValue");
    return mock;
}

0
投票

正如我所见,这是针对Rest Controller类的单元测试。

我建议按照以下惯例将测试班级命名为以下名称

类名称:StudentServer。class

Junit类名称:StudentServerTest。class

现在是您的真实问题。

1]我看到您已经自动关联了依赖类(StudentService。class。相反,您需要将其模拟为

@MockBean
private StudentService studentService;

2]您不需要在测试类中使用StringGeneratorService bean /对象,因为它的方法不会从您的控制器类中直接调用。

而是从您的服务类中调用其方法,并且由于您在模拟服务类本身,所以该类在您的控制器类中完全不可见。

删除此

@Autowired
public StringGeneratorService stringGeneratorService;

3]现在,如下定义模拟行为,然后断言

@Test
public void testGenerateStudent() throws Exception {

   Student student = new Student();
   student.setName("TestStudent");
   Mockito.when(studentService.getRandomStudent()).thenReturn(student);

   mockMvc.perform(MockMvcRequestBuilders.get("/generate-student"))
         .andExpect(MockMvcResultMatchers.status().isOk())
         .andDo(print())
         .andExpect(MockMvcResultMatchers.jsonPath("$.name").isNotEmpty());

   }
© www.soinside.com 2019 - 2024. All rights reserved.