Я новичок в модульном тестировании и не могу понять, как тестировать 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, чтобы пройти тест?
это внутри контроллера? как это сделать ?
Я посмотрю, смогу ли я написать пример позже сегодня. В основном вам нужно издеваться над modelMapper и заставить Mockito возвращать фиктивные данные всякий раз (используйте Mockito.when()), когда он вызывается, а не то, что метод обычно возвращает.
я думаю, что моя проблема связана именно с синтаксисом json jayway jsonPath ($, hasSize (2)) , $ он не может определить объект на основе $.
Что ж, это достаточно легко определить: будет ли операция по-прежнему «работать», если вместо этого вы вернете список сотрудников напрямую, а не сопоставите их с объектами DTO? Если нет, то, возможно, вы на правильном пути. В противном случае я подозреваю, что это то, о чем я уже упоминал, и вам нужно обрабатывать зависимость службы modelMapper.
Или вы можете создать шпиона и вызвать реальную службу, которая отлично работает, если вы можете предположить, что она всегда будет работать.
Еще одна проблема, которую я вижу, заключается в том, что у вас есть вызов employeService.findAllEmployeActive() в вашем контроллере, но when(employeService.findAll()) в вашем тесте. Не уверен, намеренно это или нет, но может быть частью вашей проблемы.




Я вижу несколько потенциальных проблем:
Во-первых, вы звоните
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, и я думаю, что это как-то не правильно !!
Ну, я сделал несколько предположений о том, как ваши объекты Employee преобразуются в объекты EmployeeDTO. Гарантированно ли сохраняется порядок объектов? Потому что кажется, что они находятся в другом порядке после сопоставления.
Вы мне понравились, в том же порядке я даже добавляю два конструктора, в Employed и EmployeD TO.
Ну странно... не знаю, почему так происходит
Вот код, который работает, но игнорирует объект 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 ;
}
Ваш контроллер вызывает
convertToDto(), который зависит отmodelMapper.map()отModelMapper. Вам также нужно издеваться над этим служебным вызовом