Как использовать mockito и junit для проверки моего API для весенней загрузки?

Я новичок в модульном тестировании и не могу понять, как тестировать RESTFul API с помощью Spring с использованием Mockito и Junit, прежде всего я подготовил класс, в котором я создал два метода с @До и @Контрольная работа, когда я включил его в режиме отладки говорит мне, что коллекция hasSize возвращает 0, а не 4.

@RunWith(SpringJUnit4ClassRunner.class)
public class EmployeControllerTest {
    private MockMvc mockMvc;
    @InjectMocks
    private EmployeController employeController ; 
    @Mock
    private EmployeService employeService ;

    @Before
    public void setUp() throws Exception{
        MockitoAnnotations.initMocks(this);
        mockMvc=MockMvcBuilders.standaloneSetup(employeController).build();
    }
    @Test
    public void testgetAllEmployee() throws Exception{
        List<Employe> employes= Arrays.asList(
                new Employe("Hamza", "Khadhri", "hamza1007", "123")
                ,new Employe("Oussema", "smi", "oussama", "1234") );
        when(employeService.findAll()).thenReturn(employes);
        mockMvc.perform(get("/employe/dto"))
        .andExpect(status().isOk())
        .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
        .andExpect(jsonPath("$", hasSize(4)))
         .andExpect(jsonPath("$[0].nom", is("Hamza")))
         .andExpect(jsonPath("$[0].prenom", is("Khadhri")))
         .andExpect(jsonPath("$[0].login", is("hamza1007")))
         .andExpect(jsonPath("$[0].mp", is("123")))
         .andExpect(jsonPath("$[1].nom", is("Oussema")))
         .andExpect(jsonPath("$[1].prenom", is("smi")))
         .andExpect(jsonPath("$[1].login", is("oussama")))
         .andExpect(jsonPath("$[1].mp", is("1234")));

        verify(employeService,times(1)).findAll();
        verifyNoMoreInteractions(employeService);
    }
}

вот EmployeController :

    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @RestController
    @RequestMapping("/employe")
    public class EmployeController {
        @Autowired
        private EmployeService employeService;

        @Autowired
        private ModelMapper modelMapper;

        @GetMapping("/dto")
        public List<EmployeDTO> getEmployeDTOList(){
            try {
                    List<Employe> listemp=employeService.findAllEmployeActive();
                    return listemp.stream()
                        .map(emp ->convertToDto(emp))
                        .collect(Collectors.toList());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }

        private EmployeDTO convertToDto(Employe emp) {
            EmployeDTO empDto = modelMapper.map(emp, EmployeDTO.class);

            return empDto;
       }
   }

когда я включаю режим отладки, он говорит мне, что есть NullPointerException.

Как правильно использовать mockito и junit, чтобы пройти тест?

Ваш контроллер вызывает convertToDto(), который зависит от modelMapper.map() от ModelMapper. Вам также нужно издеваться над этим служебным вызовом

Stalemate Of Tuning 05.02.2019 17:46

это внутри контроллера? как это сделать ?

Hamza Khadhri 06.02.2019 09:57

Я посмотрю, смогу ли я написать пример позже сегодня. В основном вам нужно издеваться над modelMapper и заставить Mockito возвращать фиктивные данные всякий раз (используйте Mockito.when()), когда он вызывается, а не то, что метод обычно возвращает.

Stalemate Of Tuning 06.02.2019 15:05

я думаю, что моя проблема связана именно с синтаксисом json jayway jsonPath ($, hasSize (2)) , $ он не может определить объект на основе $.

Hamza Khadhri 06.02.2019 16:20

Что ж, это достаточно легко определить: будет ли операция по-прежнему «работать», если вместо этого вы вернете список сотрудников напрямую, а не сопоставите их с объектами DTO? Если нет, то, возможно, вы на правильном пути. В противном случае я подозреваю, что это то, о чем я уже упоминал, и вам нужно обрабатывать зависимость службы modelMapper.

Stalemate Of Tuning 06.02.2019 18:03

Или вы можете создать шпиона и вызвать реальную службу, которая отлично работает, если вы можете предположить, что она всегда будет работать.

Stalemate Of Tuning 06.02.2019 18:09

Еще одна проблема, которую я вижу, заключается в том, что у вас есть вызов employeService.findAllEmployeActive() в вашем контроллере, но when(employeService.findAll()) в вашем тесте. Не уверен, намеренно это или нет, но может быть частью вашей проблемы.

Stalemate Of Tuning 06.02.2019 18:37
глянь сюда (рабочий тестовый пример весенней загрузки mvc)
xerx593 06.02.2019 20:30
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
0
8
1 974
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я вижу несколько потенциальных проблем:

Во-первых, вы звоните

List<Employe> listemp=employeService.findAllEmployeActive();

в getEmployeDTOList() вашего контроллера, но ваш макет Mockito записывается как:

when(employeService.findAll()).thenReturn(employes)

Таким образом, ваш тест может не работать просто потому, что ваш макет никогда не происходит.

Во-вторых, вы не издевались над ModelMapper, который вы автоматически подключили к своему контроллеру. Я считать Spring все равно пойдет дальше и возьмет этот компонент для вас (кто-то поправит меня, если я ошибаюсь), но в любом случае это не очень хорошая практика, чтобы ваши модульные тесты зависели от внешних библиотек, поскольку вы должны заботиться только о функциональность контроллера. Было бы лучше издеваться над ModelMapper, чтобы он работал «всегда», и писать отдельные тесты для проверки ваших сопоставлений.

Я пошел дальше и сделал свою собственную версию вашего кода, чтобы проверить. Я изменил hasSize на 2, потому что в вашем примере вы использовали только два элемента.

Этот тест работает для меня:

@RunWith(SpringJUnit4ClassRunner.class)
public class EmployeeControllerTest {

    private MockMvc mockMvc;
    @InjectMocks
    private EmployeeController employeeController ; 
    @Mock
    private EmployeeService employeeService;
    @Mock
    private ModelMapper modelMapper;

    @Before
    public void setUp() throws Exception{
        MockitoAnnotations.initMocks(this);
        mockMvc=MockMvcBuilders.standaloneSetup(employeeController).build();
    }

    @Test
    public void testgetAllEmployeeWithModelMapper() throws Exception{
        Employee emp1 = new Employee("Hamza", "Khadhri", "hamza1007", "123");
        Employee emp2 = new Employee("Oussema", "smi", "oussama", "1234");
        List<Employee> Employees= Arrays.asList(emp1, emp2);

        EmployeeDTO dto1 = new EmployeeDTO("Hamza", "Khadhri", "hamza1007", "123");
        EmployeeDTO dto2 = new EmployeeDTO("Oussema", "smi", "oussama", "1234");
        when(modelMapper.map(emp1,EmployeeDTO.class)).thenReturn(dto1);
        when(modelMapper.map(emp2,EmployeeDTO.class)).thenReturn(dto2);

        when(employeeService.findAll()).thenReturn(Employees);


        mockMvc.perform(get("/employe/dto"))
            .andExpect(status().isOk())
            .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
            .andExpect(jsonPath("$", hasSize(2)))
            .andExpect(jsonPath("$[0].nom", is("Hamza")))
            .andExpect(jsonPath("$[0].prenom", is("Khadhri")))
            .andExpect(jsonPath("$[0].login", is("hamza1007")))
            .andExpect(jsonPath("$[0].mp", is("123")))
            .andExpect(jsonPath("$[1].nom", is("Oussema")))
            .andExpect(jsonPath("$[1].prenom", is("smi")))
            .andExpect(jsonPath("$[1].login", is("oussama")))
            .andExpect(jsonPath("$[1].mp", is("1234")));

        verify(employeeService,times(1)).findAll();
        verifyNoMoreInteractions(employeeService);

    }

}

Как видите, я создаю свои собственные объекты DTO и передаю их обратно, чтобы modelMapper всегда вел себя так, как ожидается для этого модульного теста.

я понимаю ! Я интегрировал ваш метод, и он работает! Но, когда я в jsonPath("$[0].nom", is("Хамза"), консоль говорит мне, что ожидаемый Уссема не **Хамза**!!! индекс 0 работает для второго объекта emp2, и я думаю, что это как-то не правильно !!

Hamza Khadhri 07.02.2019 12:02

Ну, я сделал несколько предположений о том, как ваши объекты Employee преобразуются в объекты EmployeeDTO. Гарантированно ли сохраняется порядок объектов? Потому что кажется, что они находятся в другом порядке после сопоставления.

Stalemate Of Tuning 07.02.2019 15:05

Вы мне понравились, в том же порядке я даже добавляю два конструктора, в Employed и EmployeD TO.

Hamza Khadhri 07.02.2019 16:30

Ну странно... не знаю, почему так происходит

Stalemate Of Tuning 07.02.2019 16:36

Вот код, который работает, но игнорирует объект emp1:

 public void testgetAllEmployeeWithModelMapper() throws Exception{
         Employe emp1 = new Employe("Hamza", "Khadhri", "hamza1007", "123");
         Employe emp2 = new Employe("Oussem", "smi", "oussama", "1234");
         List<Employe> Employees= Arrays.asList(emp1, emp2);
         EmployeDTO dto1 = new EmployeDTO("Hamza", "Khadhri", "hamza1007", "123");
         EmployeDTO dto2 = new EmployeDTO("Oussem", "smi", "oussama", "1234");
         when(modelMapper.map(emp1,EmployeDTO.class)).thenReturn(dto1);
         when(modelMapper.map(emp2,EmployeDTO.class)).thenReturn(dto2);

         when(employeeService.findAll()).thenReturn(Employees);
         mockMvc.perform(get("/employe/dto"))
         .andExpect(status().isOk())
         .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
         .andExpect(jsonPath("$", hasSize(2)))
         .andExpect(jsonPath("$[0].nom", is("Hamza")))
         .andExpect(jsonPath("$[0].prenom", is("Khadhri")))
         .andExpect(jsonPath("$[0].login", is("Hamza1007")))
         .andExpect(jsonPath("$[0].mp", is("123")))
         .andExpect(jsonPath("$[1].nom", is("Oussema")))
         .andExpect(jsonPath("$[1].prenom", is("smi")))
         .andExpect(jsonPath("$[1].login", is("oussama")))
         .andExpect(jsonPath("$[1].mp", is("1234")));

     verify(employeeService,times(1)).findAll();
     verifyNoMoreInteractions(employeeService);
    }

}

Косола показывает мне, что jsonPath("$[0].nom" ожидает Уссема поэтому, когда я меняю его на Oussema, который является объектом emp2, он работает хорошо. к сожалению, он игнорирует объект emp1, содержащий Хамза, лично я просто добавляю два конструктора в Employe и EmployeDTO.

это класс Employe:

 public class Employe implements Serializable {



    @Id
    @Column(unique=true, nullable=false, precision=6)
    private Long id;
    @Column(precision=6)
    private BigDecimal cv;
    @Column(length=254)
    private String nom;
    @Column(length=254)
    private String prenom;
    @Column(length=254)
    private String login;
    @Column(length=254)
    private String mp;
    @Column(length=254)
    private String mail;
    @Column(precision=6)
    private BigDecimal idpointage;
    @Column(length=1)
    private Boolean actif;
    public Employe(String nom, String prenom, String login, String mp) {

        this.nom = nom;
        this.prenom = prenom;
        this.login = login;
        this.mp = mp;
    }

это класс EmployeDTO:

public class EmployeDTO {
        private String nom;
        private String prenom;
        private String login ; 
        private String mp ; 


        public EmployeDTO(String nom, String prenom, String login, String mp) {

            this.nom= nom ; 
            this.prenom= prenom ; 
            this.login = login ; 
            this.mp=mp ;
        }

Другие вопросы по теме