Gradle-jacoco task adds synthetic fields while the Spring application is running, causing the test to calculate the number of declared fields in the class to fail
I have this class :
public class UserPurchaseUtil {
public static final String JSON_PROP_ID = "id";
public static final String JSON_PROP_USER_ID = "user_id";
See Confluence: First Time Member Promotion (FTM)
public static final String JSON_PROP_LAST_PURCHASE_TIME = "last_purchase_time";
}
Then, I want to make sure
that I pay attention to the changes in all the values in this class, and by “following”, I want to make sure
- Every time I remove or add some constants, the test fails;
- Check all values.
So I have this test:
@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class UserPurchaseUtilTest {
@Test
public void testNumberOfConstantsAndTheirValues() {
int numberOfConstants = UserPurchaseUtil.class.getDeclaredFields().length;
just to ensure we test all the constants' values when we add new ones. Now is 3.
Assert.assertEquals(3, numberOfConstants);
Assert.assertEquals("id", UserPurchaseUtil.JSON_PROP_ID);
Assert.assertEquals("user_id", UserPurchaseUtil.JSON_PROP_USER_ID);
Assert.assertEquals("last_purchase_time", UserPurchaseUtil.JSON_PROP_LAST_PURCHASE_TIME);
}
}
However, this simple test failed :
expected:<3> but was:<4>
Expected :3
Actual :4
<Click to see difference>
So, why?
Edit:
Oh my goodness. Now when debugging, I can now see the fourth field.
private static transient boolean[] com.xxx.utils.UserPurchaseUtil.$jacocoData
This is a Spring Boot project.
Solution
Gradle jacoco-related
tasks like jacocoTestReport and jacocoTestCoverageVerification
are interfering with my reflection checks for all classes.
I found this issue :
https://github.com/jacoco/jacoco/issues/168
My code uses reflection. Why does it fail when I execute it with JaCoCo?
To collect execution data JaCoCo instruments the classes under test which adds two members to the classes: A private static field $jacocoData and a private static method $jacocoInit(). Both members are marked as synthetic.
Please change your code to ignore synthetic members. This is a good practice anyways as also the Java compiler creates synthetic members in certain situation.
I
think in this case I should ignore synthetic members when counting. isSynthetic
() means that a member is (somewhat) added by the compiler at runtime.
So it will be like:
int nonSynthetic = 0;
Field[] allFields = UserPurchaseUtil.class.getDeclaredFields();
for (Field f: allFields) {
ignore synthetic methods, which are added at runtime by jacoco (or other libraries)
if (!f.isSynthetic()) {
nonSynthetic ++;
}
}
Assert.assertEquals(3, nonSynthetic);