gzhao9 opened a new issue, #8087:
URL: https://github.com/apache/cloudstack/issues/8087

   <!--
   Verify first that your issue/request is not already reported on GitHub.
   Also test if the latest release and main branch are affected too.
   Always add information AFTER of these HTML comments, but no need to delete 
the comments.
   -->
   
   ##### ISSUE TYPE
   <!-- Pick one below and delete the rest -->
    * Improvement Request
    * Enhancement Request
   
   ##### COMPONENT NAME
   <!--
   Categorize the issue, e.g. API, VR, VPN, UI, etc.
   -->
   ~~~
   Testing
   ~~~
   
   ##### CLOUDSTACK VERSION
   <!--
   New line separated list of affected versions, commit ID for issues on main 
branch.
   -->
   
[4.18-reflections-update](https://github.com/apache/cloudstack/tree/4.18-reflections-update)
   ~~~
   4.18-reflections-update
   ~~~
   ---------
   Hi CloudStack developers, 
   
   I have noticed that a dependency `TungstenAnswer` is mocked a total 151 
times, with similar/identical  behavior across three different test suites:
   - In class 
[TungstenElementTest.java](https://github.com/apache/cloudstack/blob/8a34afa8ab8c310f24038c0069fd1ce53b4b81d5/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java),
 there were 41 identical duplicate creations in 22 test cases.
   - In class 
[TungstenFabricUtilsTest.java](https://github.com/apache/cloudstack/blob/8a34afa8ab8c310f24038c0069fd1ce53b4b81d5/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenFabricUtilsTest.java),
 there were 2 identical duplicate creations in 2 test cases.
   - In class 
[TungstenServiceImplTest.java](https://github.com/apache/cloudstack/blob/8a34afa8ab8c310f24038c0069fd1ce53b4b81d5/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImplTest.java),
 there were 53 identical duplicate creations and 55 similar duplicate creations 
in 68 test cases.
   
   The following is the duplicate code snippet I just mentioned. It has been 
repeated 96 times with completely identical logic in the 3 testclasses:
   ```java
   TungstenAnswer answer=mock(TungstenAnswer.class);
   when(answer.getResult()).thenReturn(Result);
   ```
   We can eliminate this duplication by creating a 
[CreateMockTungstenAnswer]((https://github.com/gzhao9/cloudstack/blob/refactoring-org.apache.cloudstack.network.tungsten.service/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/CreateMockTungstenAnswer.java))
 class.
   The code snippet of `CreateMockTungstenAnswer`:
   ```java
   public class CreateMockTungstenAnswer {
   //Attribute is for reuse mock creation.
       TungstenAnswer answer;
   //Implement duplicate mock and stub behavior in the constructor.
       CreateMockTungstenAnswer(boolean Result){
           answer=mock(TungstenAnswer.class);
           when(answer.getResult()).thenReturn(Result);
       }
       TungstenAnswer get(){return this.answer;}
   }
   ```
   When a mock needs to be created in a test case, we can create it with this 
class like:
   ```java
   TungstenAnswer answer=new CreateMockTungstenAnswer(true).get();
   ```
   Also, in `TungstenServiceImplTest.java`, the creation of mock for 
`TungstenAnswer` is repeated another 55 times, but with a slightly different 
stub method in mock creation. For example, in test case 
`addTungstenDefaultNetworkPolicyTest()`:
   ```java
   TungstenAnswer createTungstenPolicyAnswer=mock(TungstenAnswer.class);
   when(createTungstenPolicyAnswer.getResult()).thenReturn(true);
   // following are additional different stub from other mock creation
   
when(createTungstenPolicyAnswer.getApiObjectBase()).thenReturn(networkPolicy);
   ```
   In comparison, in the test `addTungstenDefaultNetworkPolicyTest()`, the stub 
for the 1st method is same, but there will be an additional 2nd or 3rd method 
compared to the 96 identical duplicate mock creations.
   
   We can still eliminate repetition by creating a reusable, "basic" mock 
object, but at each mock creation, we can customize the stub of the other 
methods.
   ```java
   TungstenAnswer createTungstenPolicyAnswer=new 
CreateMockTungstenAnswer(true).get();
   
   
when(createTungstenPolicyAnswer.getApiObjectBase()).thenReturn(networkPolicy);//
 Add a different stub behavior.
   ```
   To be more intuitive, the following shows the comparison of how a test case 
looks before and after the refactoring, with the code snippet of 
`syncTungstenDbWithCloudstackProjectsAndDomainsTest()` in test suit 
[TungstenServiceImplTest](https://github.com/apache/cloudstack/blob/8a34afa8ab8c310f24038c0069fd1ce53b4b81d5/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImplTest.java#L654)
 as an example:
   
   Code before refactoring:
   
   ```java
   @Test
   public void syncTungstenDbWithCloudstackProjectsAndDomainsTest() {
       // The code before this comment is the same
       TungstenAnswer createTungstenDomainAnswer = mock(TungstenAnswer.class);
       TungstenAnswer createTungstenProjectAnswer = mock(TungstenAnswer.class);
       TungstenAnswer createTungstenDefaultProjectAnswer = 
mock(TungstenAnswer.class);
       TungstenAnswer updateTungstenDefaultSecurityGroupAnswer = 
mock(TungstenAnswer.class);
   
       when(createTungstenDomainAnswer.getResult()).thenReturn(true);
       when(createTungstenProjectAnswer.getResult()).thenReturn(true);
       
when(updateTungstenDefaultSecurityGroupAnswer.getResult()).thenReturn(true);
       when(createTungstenDefaultProjectAnswer.getResult()).thenReturn(true);
   
       //The rest of the sentence is exactly the same before and after the 
refactoring.
   }
   ```
   Code after refactoring:
   
   ```java
   @Test
   public void syncTungstenDbWithCloudstackProjectsAndDomainsTest() {
       // The code before this comment is the same
       TungstenAnswer createTungstenDomainAnswer = new 
CreateMockTungstenAnswer(true).get();
       TungstenAnswer createTungstenProjectAnswer = new 
CreateMockTungstenAnswer(true).get();
       TungstenAnswer createTungstenDefaultProjectAnswer = new 
CreateMockTungstenAnswer(true).get();
       TungstenAnswer updateTungstenDefaultSecurityGroupAnswer = new 
CreateMockTungstenAnswer(true).get();
   
       //The rest of the sentence is exactly the same before and after the 
refactoring.
   }
   ```
   We've applied a similar refactoring approach to three test suites, 
[TungstenServiceImplTest.java](https://github.com/gzhao9/cloudstack/blob/refactoring-org.apache.cloudstack.network.tungsten.service/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImplTest.java),
 [TungstenFabricUtilsTest.java]() and [TungstenElementTest.java 
](https://github.com/gzhao9/cloudstack/blob/refactoring-org.apache.cloudstack.network.tungsten.service/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java).
 **As a result, we can reduce 321 lines of code, which makes the test cases 
smaller, easier to understand, and better to maintain.**
   
   **After refactoring, if the `TungstenAnswer` mock creation needs to be 
modified in the future, the developer only needs to modify one time in 
`CreateMockTungstenAnswer` instead of 151 places of duplicate mock creation in 
3 testclasses.**
   
   #### Benefits of the Proposed Refactoring:
   - **Modularity:** The code is now more modular with specific class for 
creating mock object.
   - **Readability:** Test cases are more readable, focusing on specific test 
logic rather than the setup code.
   - **Maintainability:** Easier maintenance due to the reduction of redundancy 
and a cleaner, more structured codebase.
   - **Scalability:** Facilitates the addition of new test cases and makes 
modifications to existing ones more efficient.
   
    I'd love to hear your thoughts on this proposal! Do you agree with any of 
these changes, or do you have other insights or preferences? 
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to