Link to home
Start Free TrialLog in
Avatar of gp
gpFlag for United States of America

asked on

Refactor For loop with Six if loops to better unit test

I have a method  which takes Json object with for loop and then 6 if conditions like below


public void doTransaction(ProductSt productStMessage){
List<Serial> listOfItems= ProductAdapter.parseJsonProductMessage(productStMessage);
....
...


for(int index=0; index<listOfItems,size();index++){


 if(listOfItems.get(index).getItemName().equals("Smpl"){
         if(listOfItems.get(index).getItemValueText()!=null){
                productId=listOfItems.get(index).getItemValueText().toString();
          }
       else{ productId=null}
         
 }


 if(listOfItems.get(index).getItemName().equals("Xyz"){
         if(listOfItems.get(index).getItemValueText()!=null){
                productCd=listOfItems.get(index).getItemValueText().toString();
          } else{ productCd=null}
 }


 if(listOfItems.get(index).getItemName().equals("Abc"){
         if(listOfItems.get(index).getItemValueText()!=null){                 productDes=listOfItems.get(index).getItemValueText().toString();           } else{ productDec=null}  }  if(listOfItems.get(index).getItemName().equals("Cde"){
         if(listOfItems.get(index).getItemValueText()!=null){                 productLoc=listOfItems.get(index).getItemValueText().toString();           } else{ productLoc=null}  }   if(listOfItems.get(index).getItemName().equals("Fgh"){
         if(listOfItems.get(index).getItemValueText()!=null){                 productShelf=listOfItems.get(index).getItemValueText().toString();           } else{ productShelf=null}  }  if(listOfItems.get(index).getItemName().equals("Ijk"){          if(listOfItems.get(index).getItemValueText()!=null){                 productRow=listOfItems.get(index).getItemValueText().toString();           }else{ productRow=null}  }

Open in new window



I like to refactor this code so that I can unit test each individual values coming based on Xpath kind of values coming from Json message. When I try to do using Intellij Idea by selecting entire for loop got error saying too many variables there. Please advise


Avatar of Jeffrey Dake
Jeffrey Dake
Flag of United States of America image

If I were you I would start by breaking your function apart in to small functions.  Have your functions do a small amount of work that returns something that can be tested.  I would then probably put your whole for loop in its own function that returns an object that could be tested apart.  I don't really understand the underlying concept of your code, so in my example I named it something unrealistic.  Something like:


for (Serial serial : ProductAdapter.parseJsonProductMessage(productStMessage))
   {
      if (itemNameEquals("Smpl"))
      {
         productId = getItemValue(serial);
      }
      
      if (itemNameEquals("Xyz"))
      {
         productCd = getItemValue();
      }
      
      return new ResultObjectWithNameThatMakesSense(productId, productCd);
   }
   
   public String itemNameEquals(Serial serial, String name)
   {
      return serial.getItemName().equals(name);
   }
   
   public String getItemValue(Serial serial)
   {
      Object object = serial.getItemvalueText();
      if (object != null)
         return object.toString();
      
      return null;
   }

Open in new window

Hope this makes sense our helps.  But it seems like the biggest problem to making your function untestable is that it is doing way too much


Avatar of gp

ASKER

if (itemNameEquals("Xyz"))
      {
         productCd = getItemValue();
      }

Above method only has one argument where as below method has 2 arguments right
  public String itemNameEquals(Serial serial, String name)
   {
      return serial.getItemName().equals(name);
   }


Also below should returns list of Serial custom objects instead of simple Serial custom object as below?
 List<Serial> listOfItems= ProductAdapter.parseJsonProductMessage(productStMessage);
Avatar of gp

ASKER

Any sample links, examples, resources i can refer to make my visualization and implementation faster to understand better?
Avatar of gp

ASKER

I like to keep traditional for loop instead of enhanced for loop if possible using index. How to use traditional for loop in this case?

The reason I go rid of the traditional loop was because you were doing a get() over and over again which is ver inefficient. You are doing a list scan every time. You could reduce that to one call to be more efficient but the advanced loop makes it just go through the list once.


For the arguments you are right. I forgot to include the serial object in my call, it should be passed in

Avatar of gp

ASKER

public void doTransaction(ProductSt productStMessage){
List<Serial> listOfItems= ProductAdapter.parseJsonProductMessage(productStMessage);
String productID=null;
String productCd=null;
String productDec=null;
String productLoc=null;
String productShelf=null
boolean productPresentIndicator=false;



for(int index=0; index<listOfItems,size();index++){


 if(listOfItems.get(index).getItemName().equals("Smpl"){
         if(listOfItems.get(index).getItemValueText()!=null){
               // productId=listOfItems.get(index).getItemValueText().toString();
                  productId=getProductId(listOfItems,productID,index)
          }
      // else{ productId=null}
         
 }

 if(listOfItems.get(index).getItemName().equals("Xyz"){
         if(listOfItems.get(index).getItemValueText()!=null){
             //   productCd=listOfItems.get(index).getItemValueText().toString();
               productCd=getProductCd(listOfItems,productID,index)
         // } else{ productCd=null}
 }


 if(listOfItems.get(index).getItemName().equals("Abc"){
         if(listOfItems.get(index).getItemValueText()!=null){
               // productDes=listOfItems.get(index).getItemValueText().toString();
             productDec=getProductDec(listOfItems,productID,index)
          //} else{ productDec=null}
 }
 if(listOfItems.get(index).getItemName().equals("Cde"){
         if(listOfItems.get(index).getItemValueText()!=null){
             //   productLoc=listOfItems.get(index).getItemValueText().toString();
            productLoc=getProductLoc(listOfItems,productID,index)
          //} else{ productLoc=null}
 }
  if(listOfItems.get(index).getItemName().equals("Fgh"){
         if(listOfItems.get(index).getItemValueText()!=null){
                //productShelf=listOfItems.get(index).getItemValueText().toString();
                productShelf=getProductShelf(listOfItems,productID,index)
         // } else{ productShelf=null}
 }


 if(listOfItems.get(index).getItemName().equals("Ijk"){
         if(listOfItems.get(index).getItemValueText()!=null){
                //productPresentIndicator=listOfItems.get(index).getItemValueText().toString();
             productPresentIndicator=getProductId(listOfItems,productID,index)
         // }else{ productRow=null}
 }


pubic String getProductID(List<Serial> listOfItems, String productID, int index){
    if(listOfItems.get(index).getItemValueText()!=null){
             productID=listOfItems.get(index).getItemValueText().toString)
      }
     else{
          productID=null;
      }

return productID;
}

pubic String getProductCd(List<Serial> listOfItems, String productID, int index){
...
}
pubic String getProductDec(List<Serial> listOfItems, String productID, int index){
...
}
pubic String getProductLoc(List<Serial> listOfItems, String productID, int index){
...
}
pubic String getProductShelf(List<Serial> listOfItems, String productID, int index){
..
}
pubic boolean getProductPresentIndicator(List<Serial> listOfItems, String productID, int index){
...
}

Open in new window

I updated like above.
I like to refactor whole for loop with 5 for if loops that deals with String to be returned and last if loop deals with boolean type to be returned. This refactored method should take listOfItems as input(which obtained from productStMessage original argument of original parent doTransaction() method and return some data structure/collection object including those 5 Strings, 1 boolean value
ASKER CERTIFIED SOLUTION
Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of gp

ASKER

How to make new method to take listOfItems as input and output some data structure
It looks like you are asking a different question here, so you'd really have to open another thread for that.
Actually the code I posted should have been more like this :
public void doTransaction(ProductSt productStMessage){
List<Serial> listOfItems= ProductAdapter.parseJsonProductMessage(productStMessage);
....
...

Serial thisSerial;
String itemName;


 for(int index=0; index<listOfItems,size();index++){

        thisSerial = listOfItems.get(index);
        itemName = thisSerial.getItemName().toString();    
  
    
    switch (itemName){
    
        case "Smpl": 
            productID = thisSerial.getItemValueText()!=null?thisSerial.getItemValueText().toString():null;
        break;
        
        case "Xyz":
            productCd = thisSerial.getItemValueText()!=null?thisSerial.getItemValueText().toString():null;        
        break;
        
        case "Ijk": 
            productRow = thisSerial.getItemValueText()!=null?thisSerial.getItemValueText().toString():null; 
        break;
               
        .
        .
        .
        
    
    }
  }
}

Open in new window


Hope that's more like it.