如何在mockito中测试循环内部循环

时间:2014-02-19 10:47:28

标签: junit mockito

我有方法insertOrUpdateProductsToDB(Product product)用于使用Broadleaf的catalogService在数据库中执行插入操作,目录服务正在db中执行所有保存操作。我的方法是预期restClient产品作为参数。在传递restClient产品后,我们使用ProductConversion Class将此产品转换为Broadleafproduct。在产品转换中,仅将设置转换为将产品转换为broadleafproduct。现在我的要求是使用mockito测试这个方法但是当我试图在我的测试方法结束时添加这两行

verify(mainProduct).getAdditionalSkus().add(sku);
       verify(mainProduct).setProductOptions(productOptionList);

失败了。

当我调试代码时,方法insertOrUpdateProductsToDB(Product product)中有for循环for循环,我发现productOption = catalogService.saveProductOption(productOption);这里productOption是null,所以请告诉我如何测试循环内部循环和< / p>

for (Sku skuWithProductOptions : productConversion.createSkuWithProductOptions(product, mainProduct,productOptionList)) {
                    catalogService.saveSku(skuWithProductOptions);
                }

这一行采用相同的方法。也请检查我的测试用例是否正确。

类和insertOrUpdateProductsToDB(Product product)要测试的方法

import com.admin.exception.AdminGenericException;
import com.admin.exception.AdminRestException;
import com.admin.util.helper.ProductConversion;
import com.admin.wrapper.getproducts.req.ObjectFactory;
import com.admin.wrapper.getproducts.resp.Product;
import com.admin.wrapper.getproducts.resp.Response;
import com.mycompany.rest.service.client.RestClientUtil;
import com.mycompany.util.constants.ApplicationConstants;

@Service
public class GetProductsServiceImpl {

    private static final Logger logger = Logger.getLogger(GetProductsServiceImpl.class);

    @Resource(name = "blCatalogService")
    protected CatalogService catalogService;

    public void setCatalogService(CatalogService catalogService) {
        this.catalogService = catalogService;
    }

    protected RestClientUtil restClientUtil;

    public void setRestClientUtil(RestClientUtil restClientUtil) {
        this.restClientUtil = restClientUtil;
    }

    @Value("#{configProperties['salePriceRate']}")
    private long salePriceRate;

    public void setRetailPriceRate(long retailPriceRate) {
        this.retailPriceRate = retailPriceRate;
    }

    @Value("#{configProperties['retailPriceRate']}")
    private long retailPriceRate;

    public void setSalePriceRate(long salePriceRate) {
        this.salePriceRate = salePriceRate;
    }


   //Insertion/Update DB logic
    public String insertOrUpdateProductsToDB(Product product) {
        logger.debug("Start of : insertOrUpdateProductsToDB()");
        try {
            List<String> category = new ArrayList<String>         (Arrays.asList(ApplicationConstants.CATEGORY));
            ProductConversion productConversion = new ProductConversion();
            List<ProductOption> productOptionList = new ArrayList<ProductOption>();
                if (category.contains(product.getCategory().toUpperCase())) {
                    org.broadleafcommerce.core.catalog.domain.Product mainProduct=catalogService.createProduct(new ProductType("org.broadleafcommerce.core.catalog.domain.Product", "Normal Product"));
                    mainProduct = productConversion.createProduct(mainProduct,product);
                    Sku sku=catalogService.createSku();
                    mainProduct.setDefaultSku(sku);
                    mainProduct = productConversion.addSkuToProduct(mainProduct, product, salePriceRate,retailPriceRate);
                    for (ProductOption productOption : productConversion.createProductOptions(product, mainProduct)) {
                        productOption.setAllowedValues(productConversion.createProductOptionValues(product,productOption));
                        productOption = catalogService.saveProductOption(productOption);
                        productOptionList.add(productOption);
                    }
                    sku = catalogService.saveSku(mainProduct.getDefaultSku());
                    mainProduct.getAdditionalSkus().add(sku);
                    mainProduct.setProductOptions(productOptionList);
                    mainProduct = catalogService.saveProduct(mainProduct);
                    for (Sku skuWithProductOptions : productConversion.createSkuWithProductOptions(product, mainProduct,productOptionList)) {
                        catalogService.saveSku(skuWithProductOptions);
                    }
                }
        logger.debug("End of : insertOrUpdateProductsToDB()");
        return "Product inserted into DB successfully";
       }
     catch (Exception e) {
        logger.error("Error:", e);
        return "Insertion of product into DB Failed ";
    }
  }
 //Insertion service for DB
  public String insertProductsIntoDB(){
         logger.debug("Start of : insertProductsIntoDB()");
         int insertionCount=0;
           try{
              com.admin.wrapper.getproducts.resp.Response resp = getAvailableProductsFromPBS();
              for (Product product : resp.getProducts().getProduct()) {
                    if(catalogService.findProductById(Long.parseLong(product.getId()))==null){
                        String str=insertOrUpdateProductsToDB(product);
                        if(str.equalsIgnoreCase("Product inserted into DB successfully")){
                            insertionCount=insertionCount+1;
                        }
                       }
                    }
              logger.debug(insertionCount+" Products inserted into DB successfully");
              logger.debug("End of : insertProductsIntoDB()");
              return insertionCount+" Products inserted into DB successfully";
           }catch (AdminRestException e) {
                logger.error("Error:", e);
                return e.getMessage();
           }
    }

}

我的测试用例类和方法

public class GetProductsServiceImplTest {
    private CatalogService catalogService;
    private RestClientUtil restClientUtil;
    private GetProductsServiceImpl getProductsServiceImpl;
    private org.broadleafcommerce.core.catalog.domain.Product mainProduct;
    private Sku sku;
    private  ProductOption productOption;
    private List<ProductOption> productOptionList;


    @Before
    public void setUp() throws Exception {
        catalogService = mock(CatalogService.class);
        productOptionList=mock(List.class);
        mainProduct = spy(new ProductImpl()); 
        sku =  new SkuImpl();
        getProductsServiceImpl = new GetProductsServiceImpl();
        getProductsServiceImpl.setCatalogService(catalogService);
        productOption=mock(ProductOption.class);
        restClientUtil = new RestClientUtil();


    }

    @Test
    public void testInsertOrUpdateProductsToDB() {

    restClientUtil.setSellerCode("1");
    restClientUtil.setPbsUrl("http://10.52.165.239:8080/pbs");
    getProductsServiceImpl.setRestClientUtil(restClientUtil);
    Response pbsResponse = getProductsServiceImpl
        .getAvailableProductsFromPBS();
        for (Product pbsProduct : pbsResponse.getProducts().getProduct()) {
            when(catalogService.createProduct(new ProductType("org.broadleafcommerce.core.catalog.domain.Product","Normal Product"))).thenReturn(mainProduct);
            when(catalogService.createSku()).thenReturn(sku);
            when(catalogService.saveProductOption(productOption)).thenReturn(productOption);
            when(catalogService.saveSku(sku)).thenReturn(sku);
            when(catalogService.saveProduct(mainProduct)).thenReturn(mainProduct);
            when(catalogService.saveSku(sku)).thenReturn(sku);
            getProductsServiceImpl.insertOrUpdateProductsToDB(pbsProduct);
            verify(mainProduct,times(2)).setDefaultSku(sku);
           verify(mainProduct).getAdditionalSkus().add(sku);
           verify(mainProduct).setProductOptions(productOptionList);

            break;          
        }
        }
}

这是测试时的错误

   java.lang.NullPointerException
    at com.admin.api.service.getproducts.test.GetProductsServiceImplTest.testInsertOrUpdateProductsToDB(GetProductsServiceImplTest.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)

1 个答案:

答案 0 :(得分:1)

我有一些评论可能无法回答你的问题。但我希望他们能引导您更好地重构此代码。您展示的代码示例也不足以指出您的确切问题;它是测试方法中的NPE,所以追踪它不应该那么困难。

在这里说的是我想提出的观点

  • 测试代码非常精心制作,在我看来,这段代码过度使用了Mockito。总的来说,这段代码看起来太复杂,无论如何都无法正确测试。我不认为它是按照TDD原则编码的( TDD在测试和设计应用程序时非常方便

  • 您可能希望在单个方法中遵循通用准则不超过10行代码,这通常有助于区分问题并识别更简单的代码/意图。如果设计正确(不泄漏概念或变量),可以更轻松地更改和测试这些更简单的代码。例如,您可能希望提取一种方法来保存单个Product并仅测试该方法。

  • 更令人惊讶的是,这段代码看起来有点程序化(即使是内部对象)。并没有真正解释商业词汇的意图(好吧,关于在DB中保存东西,但出于这个原因,所有这些逻辑,这个原因应该出现在方法名称中)。 / p>

  • 测试和Mockito很奇怪,代码不应该迭代集合到存根然后验证

    for (Product pbsProduct : pbsResponse.getProducts().getProduct()) {
        when(catalogService.createProduct(new ProductType("org.broadleafcommerce.core.catalog.domain.Product","Normal Product"))).thenReturn(mainProduct);
        when(catalogService.createSku()).thenReturn(sku);
        when(catalogService.saveProductOption(productOption)).thenReturn(productOption);
        when(catalogService.saveSku(sku)).thenReturn(sku);
        when(catalogService.saveProduct(mainProduct)).thenReturn(mainProduct);
        when(catalogService.saveSku(sku)).thenReturn(sku);
        getProductsServiceImpl.insertOrUpdateProductsToDB(pbsProduct);
        verify(mainProduct,times(2)).setDefaultSku(sku);
        verify(mainProduct).getAdditionalSkus().add(sku);
        verify(mainProduct).setProductOptions(productOptionList);
    
        break;
    }
    
  • 在伪代码中,我首先尝试使用给定 / / 然后 BBDD关键字(他们)时提取保存逻辑有助于澄清在哪种场景和背景下需要测试的内容)。将夹具和断言保持在最低限度,您宁愿处理多种测试方法而不是多种复杂的测试方法。

    @Test
    public void ensure_product_is_saved_in_the_catalog() {
        // given
        Product a_simple_product = ProductBuilder.simpleProduct().build();
        when(catalogService.doSomething(....))).thenReturn(mainProduct);
    
        // when 
        productsService.saveProduct(product);
    
        // then
        verify(catalogService).doSomethingElseWith(mainProduct);
    }
    

如果产品数据的断言与测试场景相关,则编写一个实际测试数据的测试(使用JUnit断言,AssertJ,...)。不要嘲笑Product

逐步进行每个测试,然后重构,如果需要ed以保持代码可管理(如果需要,在另一个类中提取单个方法等)。

希望有所帮助。