Я впервые создаю службу REST, используя Webflux и Reactive Mon go.
Вот мой контроллер и инструмент реализации:
Контроллер:
@RestController
@RequestMapping("/endpoint/computer")
@RequiredArgsConstructor
public class ComputerEndpoint {
private final ComputerServiceImpl computerService;
@PostMapping
@ResponseStatus(code = HttpStatus.CREATED)
public Mono<Computer> createNewComputer(@Valid @RequestBody Computer computer) {
return computerService.create(computer);
}
@GetMapping
public Flux<Computer> findAllComputer() {
return computerService.findAll();
}
@GetMapping("/{id}")
public Mono<Computer> findOneComputer(@PathVariable("id") String id) {
return computerService.findById(id);
}
@PutMapping("/{id}")
public Mono<Computer> updateOneComputer(@PathVariable("id") String id, @Valid @RequestBody Computer parsedBody) {
return computerService.update(id, parsedBody);
}
@DeleteMapping("/{id}")
public Mono<Void> deleteOneComputer(@PathVariable("id") String id) {
return computerService.deleteById(id);
}
}
ServiceImpl:
@Service
@RequiredArgsConstructor
public class ComputerServiceImpl implements ComputerService {
private final ComputerRepository repo;
@Override
public Flux<Computer> findAll() {
return repo.findAll();
}
@Override
public Mono<Computer> findById(String id) {
return repo.findById(id)
.switchIfEmpty(Mono.error(new Exception("COMPUTER_NOT_FOUND")));
}
@Override
public Flux<Computer> saveAll(List<Computer> computers) {
return repo.saveAll(computers);
}
@Override
public Mono<Computer> create(Computer computer) {
return repo.save(computer);
}
@Override
public Mono<Computer> update(String id, Computer computer) {
return repo.findById(id)
.switchIfEmpty(Mono.error(new Exception("COMPUTER_NOT_FOUND")))
.map(c -> {
computer.setId(id);
return computer;
})
.flatMap(repo::save);
}
@Override
public Mono<Void> delete(Computer computer) {
return repo.delete(computer);
}
@Override
public Mono<Void> deleteById(String id) {
return repo.deleteById(id);
}
@Override
public Mono<Void> deleteAll() {
return repo.deleteAll();
}
}
И принцип Reactive Stream (Mono и Flux) для меня довольно новый. Затем я пытаюсь написать тест для этих методов, используя JUnit 5 и Mockito.
Test:
@ExtendWith(SpringExtension.class)
@WebFluxTest(controllers = ComputerEndpoint.class)
@Import(ComputerServiceImpl.class)
class ComputerEndpointTest {
@MockBean
ComputerServiceImpl service;
@Autowired
private WebTestClient client;
@Test
void createNewComputer() {
Computer computer = new Computer();
computer.setName("DESKTOP PC");
computer.setComputerModel("OptiPlex 7020");
computer.setComputerSpecs("Q87 Mainboard, i5-4590, 16Gb Ram, 1TB HDD, 256Gb SSD, 300W PSU");
Mockito.when(service.create(computer)).thenReturn(Mono.just(computer));
client.post()
.uri("/endpoint/computer")
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(computer))
.exchange()
.expectStatus().isCreated();
Mockito.verify(service, Mockito.times(1)).create(computer);
}
@Test
void findAllComputer() {
Computer computer1 = new Computer();
computer1.setName("DELL WORKSTATION");
computer1.setComputerModel("OptiPlex 7020 Ultra");
computer1.setComputerSpecs("Q87 Mainboard, i5-4590, 16Gb Ram, 1TB HDD, 256Gb SSD, 300W PSU");
Computer computer2 = new Computer();
computer2.setName("DELL PC");
computer2.setComputerModel("OptiPlex 7020 Power");
computer2.setComputerSpecs("Q87 Mainboard, i3-4150, 8Gb Ram, 500Gb HDD, 120Gb SSD, 300W PSU");
Mockito.when(service.findAll()).thenReturn(Flux.just(computer1, computer2));
client.get()
.uri("/endpoint/computer")
.exchange()
.expectStatus().isOk()
.expectBodyList(Computer.class);
Mockito.verify(service, Mockito.times(1)).findAll();
}
@Test
void findOneComputer() {
Computer computer = new Computer();
computer.setId("3b241101-e2bb-4255-8caf-4136c566a962");
computer.setName("DESKTOP PC");
computer.setComputerModel("OptiPlex 7020");
computer.setComputerSpecs("Q87 Mainboard, i5-4590, 16Gb Ram, 1TB HDD, 256Gb SSD, 300W PSU");
Mockito.when(service.findById(computer.getId())).thenReturn(Mono.just(computer));
client.get()
.uri("/endpoint/computer/{id}", computer.getId())
.exchange()
.expectStatus().isOk()
.expectBody(Computer.class);
Mockito.verify(service, Mockito.times(1)).findById(computer.getId());
}
@Test
void updateOneComputer() {
Computer computerOrigin = new Computer();
computerOrigin.setId("3b241101-e2bb-4255-8caf-4136c566a962");
computerOrigin.setName("DESKTOP PC");
computerOrigin.setComputerModel("OptiPlex 7020");
computerOrigin.setComputerSpecs("Q87 Mainboard, i5-4590, 16Gb Ram, 1TB HDD, 256Gb SSD, 300W PSU");
Computer computerUpdated = new Computer();
computerUpdated.setName("DELL PC");
computerUpdated.setComputerModel("OptiPlex 7020 Power");
computerUpdated.setComputerSpecs("Q87 Mainboard, i3-4150, 8Gb Ram, 500Gb HDD, 120Gb SSD, 300W PSU");
Mockito.when(service.update(computerOrigin.getId(), computerUpdated))
.thenReturn(Mono.just(computerOrigin));
client.put()
.uri("/endpoint/computer/{id}", computerOrigin.getId())
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(computerUpdated))
.exchange()
.expectStatus().isOk();
Mockito.verify(service, Mockito.times(1)).update(computerOrigin.getId(), computerUpdated);
}
@Test
void deleteOneComputer() {
Computer computer = new Computer();
computer.setId("3b241101-e2bb-4255-8caf-4136c566a962");
computer.setName("DESKTOP PC");
computer.setComputerModel("OptiPlex 7020");
computer.setComputerSpecs("Q87 Mainboard, i5-4590, 16Gb Ram, 1TB HDD, 256Gb SSD, 300W PSU");
Mockito.when(service.deleteById(computer.getId())).thenReturn(Mono.empty());
System.out.println(service.findById(computer.getId()));
client.delete()
.uri("/endpoint/computer/{id}", computer.getId())
.exchange()
.expectStatus().isOk();
Mockito.verify(service, Mockito.times(1)).deleteById(computer.getId());
}
}
Все тесты пройдены. Но я не уверен, что процессы насмешки были сделаны правильно, и ожидания оправдываются без каких-либо настойчивостей в издевательствах. Особенно с тестом на удаление, когда я сомневался в том, чтобы удалить его идентификатор без сохранения.
Итак, вопрос в том, как правильно написать тест реактивных сервисов и как настроить ожидание на все, чтобы действительно пройти тест?
Я могу сбить с толку атм, но, пожалуйста, помогите.