Правильные способы тестирования REST API Webflux - PullRequest
0 голосов
/ 10 марта 2020

Я впервые создаю службу 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());

    }
}

Все тесты пройдены. Но я не уверен, что процессы насмешки были сделаны правильно, и ожидания оправдываются без каких-либо настойчивостей в издевательствах. Особенно с тестом на удаление, когда я сомневался в том, чтобы удалить его идентификатор без сохранения.

Итак, вопрос в том, как правильно написать тест реактивных сервисов и как настроить ожидание на все, чтобы действительно пройти тест?

Я могу сбить с толку атм, но, пожалуйста, помогите.

1 Ответ

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

Это выглядит хорошо. Просто помните, что вы действительно тестируете свой URL -> отображение контроллера, контроллер -> отображение службы, безопасность URL, глагол http, аннотации полезной нагрузки и т. Д. c.

Вероятно, вы захотите написать отдельные интеграционные тесты для фактической реализации сервиса.

...