当前位置: 首页 > 知识库问答 >
问题:

测试WebFlup REST API的正确方法

骆昊阳
2023-03-14

我第一次使用WebFlow和Reactive Mongo构建REST服务。

这是我的控制器和服务工具:

控制器:

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

而反应流(Mono和Flux)的原理对我来说是非常新的。然后我尝试使用JUnit 5和Mockito为这些方法编写一些测试。

测试:

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

    }
}

所有测试都通过了。但我不确定模拟过程是否正确,在没有任何持续模拟的情况下,是否满足了预期。尤其是在delete测试中,当我怀疑在没有持久化的情况下删除其Id的模拟时。

所以问题是,哪种方法是编写反应式服务测试的正确方法,以及如何设置期望值以满足所有要求,从而真正通过测试?

我可能弄糊涂了,但请帮忙。

共有1个答案

施洛城
2023-03-14

这看起来不错。请记住,你真的在测试你的url-

您可能希望为实际服务实现编写单独的集成测试。

 类似资料:
  • 问题内容: 我正在尝试以编程方式测试网站列表的加载时间。目的是大致模拟用户将感知的页面加载时间。 我的第一种方法是在循环内调用以下代码: 问题是有时我会在页面真正加载之前得到时间结果(即我获得50ms次),因此我猜想控件在完成之前会移交给下一条指令。 我应该怎么做才能改善这项测试? 编辑: 正如user1258245所建议的那样,我可以等待元素加载,但是问题是我不知道哪些页面需要预先加载。 问题答

  • 问题内容: 我正在尝试以编程方式测试网站列表的加载时间。目的是大致模拟用户将感知的页面加载时间。 我的第一种方法是在循环内调用以下代码: 问题是有时我会在页面真正加载之前得到时间结果(即,我得到50ms次),所以我猜想控件在完成之前会交给下一条指令。 我应该怎么做才能改善这项测试? 编辑: 正如user1258245建议的那样,我可以等待元素加载,但是问题是我不知道哪些页面需要预先加载。 问题答案

  • 我从Codibility的代码测试练习中发现了以下问题: 给出了一个由N个不同整数组成的零索引数组A,该数组包含范围[1...(N 1)]的整数,这意味着正好缺少一个元素。 你的目标是找到缺失的元素。 编写一个函数: 类解决方案{公共int解决方案(int[]A);} 即,给定一个索引为零的数组A,返回缺失元素的值。 例如,给定一个数组: A[0]=2A[1]=3A[2]=1A[3]=5 函数应该

  • 问题内容: 我想编写一个接受参数的函数,该参数可以是序列或单个值。值的类型为str,int等,但我 不 希望将其限制为硬编码列表。换句话说,我想知道参数X是一个序列还是必须转换为序列的对象,以避免以后出现特殊情况。我可以做 但是可能还有我不知道的其他序列类型,也没有通用的基类。 -N。 编辑 :请参阅下面的“答案”,了解其中大多数答案对我没有帮助的原因。也许您有更好的建议。 问题答案: 上述所有方

  • 问题内容: 我想减少我们的构建(使用ant)运行测试所花费的时间。目前,我使用的是default ,它 在每个测试类 () 上派生一个新的虚拟机 。 我正在考虑改用,但 不确定是否会 以某种方式 耦合测试, 并可能在运行测试后给我假阳性和/或假阴性结果。 问题: 每个测试用例是否都会获得一个新的ClassLoader, 以便不再可以访问/查看以前运行的所有静态引用? 是否还有 其他 导致测试依赖/

  • 我正在尝试将powermock和mockito与Spring一起使用。我以前用过,但没有Spring。Spring-cloud-stream-test-support已经提供了和一些其他依赖项。Mockito在这个JUnit版本中也运行良好。 但是,我必须模拟一些静态方法调用,所以我需要使用PowerMock。我已经尝试将Powermock包含在JUnit和Mockito的这些版本中。 JUnit