【问题标题】:How to workaround orElseThrow mock如何解决 orElseThrow 模拟
【发布时间】:2021-08-15 16:39:02
【问题描述】:

我有一个ProductService,它通过ProductRepository 查询数据库。在那里我有一个更新方法和一个查找方法。更新方法为updateProductInDatabase(String id, Product updateInfo)updateProductInDatabase 调用方法 findProductInDatabaseById(String id),该方法返回 Product 或抛出 ResourceNotFoundException。

我的代码:

public void updateProductInDatabase(String id, Product updateInfo) {
   Product product = findProductInDatabaseById(id);
   if (correctFormat(updateInfo.getVersion()) {
       product.setVersion(updateInfo.getVersion());
       repository.save(updateInfo);
       //restOfTheCode
   } else {
       // Throws invalid input exception
   }
}

private Products findProductInDatabaseById(String id) {
   Optional<Product> productOptional = 
        repository.getAllProducts().stream.findFirst(); // return a list, but I only need the first
   return productOptional.orElseThrow(...) // Throws resource not found exception
}

我想为此代码编写单元测试,该代码预期输入无效异常,但测试失败

意外异常:预期 InvalidInputException,但发现 ResourceNotFoundException

发生这种情况是因为 productOptional 始终是一个空的可选项。

有人可以帮助提供模拟 productOptional 的解决方法吗?

编辑:添加我的测试

    @Test(expected = InvalidInputException.class)
public void testUpdateProductVersionInDatabaseWhenVersionIsIncorrectFormat()
        throws ApiException {
    Product product = new Product();
    product.setVersion("error-version");
    when(repository.getAllProducts())
            .thenReturn(Collections.singletonList(new Product()));
    productService.updateProductInDatabase("product-id-1", product);
}

【问题讨论】:

  • 请分享一个测试
  • @YuriyTsarkov 我刚刚添加了测试
  • 好吧,你抛出了一个ResourceNotFoundException,但是InvalidInputException按预期放置了,那么有什么问题吗?将期望值更改为 ResourceNotFoundException
  • 我不希望ResourceNotFoundException 被抛出,我希望服务在检查版本格式后抛出InvalidInputException
  • 您的代码没有多大意义。尤其是 findProductInDatabaseById: void 方法,它返回一些东西并且从不关心 ID。那么你能提供正确的代码吗?进一步:ResourceNotFoundException-> 这是您在orElseThrow 中声明为供应商的自定义异常吗?

标签: java mockito


【解决方案1】:

你可以做类似的事情

List<Product> products = new LinkedList<>();
products.add(new Product()); // add product

Mockito.when(repository.getAllProducts()).thenReturn(products);

【讨论】:

  • 是的,我已经这样做了 when(repository.getAllProducts(any())).thenReturn(Collections.singletonList(new Product()));
  • 你调用的repository.getAllProducts没有带任何参数,所以你需要再添加一个when(repository.getAllProducts()).thenReturn那个没有任何参数
  • 我的错误,我从另一个测试其他方法 getAllProducts(id) 的测试用例中复制了它(这也不起作用)
  • 只是覆盖了所有的基础,你的存储库声明是用@Mock 注释的?并且 productService 正在使用这个模拟存储库。
  • 是的,但不知何故可选产品是空的
【解决方案2】:

这意味着数据库的状态不适合测试,因为您期望一些数据意味着没有产品。测试前插入一些产品。 如果你真的不关心数据,那么是的,它可以被嘲笑:

class ProductServiceTestClass {
  @Mock
  ProductRepository repository;

  @InjectMocks
  ProductService productService;

    @Test(expected = InvalidInputException.class)
    public void testUpdateProductVersionInDatabaseWhenVersionIsIncorrectFormat()
            throws ApiException {
        Product product = new Product();
        product.setVersion("error-version");
        when(repository.getAllProducts())
                .thenReturn(Collections.singletonList(new Product()));
        productService.updateProductInDatabase("product-id-1", product);
    }
}

请注意,如果ProductRepository@Autowired 注入,它将不起作用。在这种情况下,将使用真正的 Spring bean。将其注入更改为构造函数或设置方法。

【讨论】:

  • 我的代码与您发布的代码相同,但它仍然从 findProductInDatabaseById 方法抛出 ResourceNotFoundException
  • 用构造函数注入了,但还是不行
  • 你在调试时看到注入的模拟吗?
【解决方案3】:

您应该重构代码,以便可以对验证方法进行单元测试

提取方法correctFormat(updateInfo.getVersion() 到一个实用程序类,如: VersionValidator.isCorrectFormat(String version)

您将能够对其进行单元测试:

@Test
public void should_return_false_on_incorrect_format_version()
        throws ApiException {
    String uncorrectFormat = "LTS.x.v15dssdf";
    boolean isCorrect = VersionValidator.isCorrectFormat(uncorrectFormat);
    assertThat(isCorrect).isFalse()
}

无论如何,如果您想继续进行集成测试,您的方法repository.getAllProducts() 至少应该返回一个产品。

public void updateProductInDatabase(String id, Product updateInfo) {
   if (!correctFormat(updateInfo.getVersion()) {
       //throw
   }
   Product product = findProductInDatabaseById(id);
   product.setVersion(updateInfo.getVersion());
   repository.save(updateInfo);
   //restOfTheCode
   
}

【讨论】:

    猜你喜欢
    • 2023-02-03
    • 2020-05-10
    • 2022-01-18
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    • 2022-12-22
    • 2022-01-10
    相关资源
    最近更新 更多