JUnit с Spring Boot на n-уровневом уровне обслуживания - PullRequest
1 голос
/ 12 апреля 2020

У меня есть модель

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

    }
}

В результате Body = {"name": null}

Может кто-нибудь иметь представление, что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 12 апреля 2020

Как я вижу, это модульный тест для вашего класса Rest Controller.

Я бы предложил назвать класс тестирования, как показано ниже, в качестве хорошей практики

Имя класса: StudentServer .class

Имя класса Junit: StudentServerTest .class

Теперь перейдем к вашей реальной проблеме.

1] Я вижу, вы автоматически подключили свой класс зависимостей ( StudentService .class). Вместо этого вам нужно смоделировать его как

@MockBean
private StudentService studentService;

2]. Вам не нужен StringGeneratorService bean / object в вашем тестовом классе, потому что его метод не вызывается напрямую из вашего класса контроллера.

Его метод вместо этого вызывается из вашего класса обслуживания, и, поскольку вы сами высмеиваете свой класс обслуживания, этот класс вообще не виден в вашем классе контроллера.

Удалите это

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

   }
0 голосов
/ 12 апреля 2020

В вашей тестовой конфигурации, чтобы определить макет для вашего StringGeneratorService: return 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;
}
...