使用 mockito 测试周围的 try catch 方法

Posted

技术标签:

【中文标题】使用 mockito 测试周围的 try catch 方法【英文标题】:Testing surrounding try catch method with mockito 【发布时间】:2021-05-02 12:50:46 【问题描述】:

我想知道如何测试此方法并强制异常“DataAccessResourceFailureException”,但我没有有效的方法。

我需要在“ProductRepositoryImpl”类中强制执行该异常。有什么想法吗?

ProductRepositoryImpl

  @Override
  public Product saveProduct(Product input) 
  try 
    return productRepositoryAdapter.saveProduct(input);
   catch (DataAccessResourceFailureException e) 
    logger.error(ERROR_WHEN_SAVING_PRODUCT_DATA_DETAIL + e.getMessage());
  
    return null;
  

ProductRepositoryAdapter

  public Product saveProduct(Product input) throws DataAccessResourceFailureException 
    ProductData productData = UtilTransform.productToProductData(input);

    // This method throws exception when there's no connection
    Product createdProduct = productDataRepository.findSkuByCountry(input.getSku(), 
    input.getCountry());

    if (createdProduct == null) 
       return Product.fromModel(productDataRepository.save(productData));
     else 
      logger.error(THE_PRODUCT_ALREADY_EXISTS_IN_THE_RECORDS);
    
      return null;
  

ProductDataRepository

public interface ProductDataRepository extends MongoRepository<ProductData, String> 

  @Query("'sku': ?0, 'country': ?1")
  public Product findSkuByCountry(String sku, String country);

  public Optional<ProductData> findById(ProductId id);

我的测试,我正在使用 mockito。

@Test
void saveProductException() 
  Mockito.when(productRepository.saveProduct(buildProduct())).thenReturn(buildProduct());
  Mockito.when(adapter.saveProduct(buildProduct())).
      thenThrow(DataAccessResourceFailureException.class);

  Assertions.assertThrows(DataAccessResourceFailureException.class, 
  () -> productRepository.saveProduct(buildProduct()));

错误:

org.opentest4j.AssertionFailedError: Expected org.springframework.dao.DataAccessResourceFailureException to be thrown, but nothing was thrown.

编辑。

我稍微改变了我的方法,使用这段代码(谢谢大家)我能够抛出异常,所以我的代码将返回 null。在检查我的 jacoco index.html 之后,我可以看到它成功覆盖了“异常”。

  @Test
  void saveProductException() 
    Product product = buildProduct();
    Mockito.when(adapter.saveProduct(product)).
       thenThrow(DataAccessResourceFailureException.class);
   Assertions.assertNull(productRepository.saveProduct(product));
  

【问题讨论】:

当异常被捕获时,您正在测试的函数不会抛出。它只是返回空值。 assertThat(productRepository.saveProduct(buildProduct())).isNull(); @xtratic 我错过了那部分。但话又说回来,他永远不会看到异常沸腾,因为适配器不会被调用。 你想在这里测试什么类?如果是repository,就不能mock了。 作为旁注;我会将 buildProduct() 的结果绑定到一个变量并重新使用该对象,这样您就可以确定它会在所有模拟配置中匹配 @NicoVanBelle 谢谢队友!!现在可以了。 【参考方案1】:

这似乎很可疑:

Mockito.when(   productRepository.saveProduct(buildProduct())   ).thenReturn(buildProduct());
. . .
Assertions.assertThrows(DataAccessResourceFailureException.class, 
        () ->   productRepository.saveProduct(buildProduct())   );

你是说,当productRepository.saveProduct(buildProduct()) 被调用时返回buildProduct(),但是你断言当它被调用时它应该抛出DataAccessResourceFailureException

不妨试试这个:

@Test
void saveProductException() 
    // as NicoVanBelle recommends, ensure you're referencing the same product throughout this test
    Product product = buildProduct();
    Mockito.when(adapter.saveProduct(product).thenThrow(DataAccessResourceFailureException.class);

    // Also as NicoVanBelle points out, when your `adapter` throws, `saveProduct` will return `null`
    Assertions.assertThat(productRepository.saveProduct(product)).isNull();

【讨论】:

谢谢!!对你和@NicoVanBelle,最后用这段代码我能够抛出异常并用“assertNull”得到它,因为如果我的代码中有异常,那么它将返回null。【参考方案2】:

我怀疑这里有两件事

    您已将 productRepository.saveProduct 设置为不抛出异常,然后断言它抛出异常

Assertions.assertThrows(DataAccessResourceFailureException.class, () -&gt; productRepository.saveProduct(buildProduct()));

    您正在调用 buildProduct(),我假设它会返回新产品,但 mockito 会尝试检查参数是否相等,因此将其取出为 Product myProduct = buildProduct() 并使用 myProduct
@Test
void saveProductException() 
  Product myProduct = buildProduct();
  
    Mockito.when(productRepository.saveProduct(myProduct))
          .thenThrow(DataAccessResourceFailureException.class);;
  
    Mockito.when(adapter.saveProduct(buildProduct())).
      thenThrow(DataAccessResourceFailureException.class);

    Assertions.assertThrows(DataAccessResourceFailureException.class, 
         () -> productRepository.saveProduct(myProduct));

【讨论】:

感谢您的回复!我测试了,但我还有一些问题。现在我想出了如何解决它(我更新了主线程)无论如何感谢您的时间@Pavan!

以上是关于使用 mockito 测试周围的 try catch 方法的主要内容,如果未能解决你的问题,请参考以下文章

模拟无效方法的try catch块并使用EasyMock或Mockito捕获异常

android单元测试框架Mockito使用

使用 Mockito 测试抽象类

使用 Mockito 测试抽象类

Junit/Mockito:选择使用模拟或集成测试运行测试

使用 Mockito 进行模拟测试的含义是啥 [重复]