How to test that Annotation @ApiModelProprty is present on all fields of a class?

+1 vote
851 views
asked Nov 21, 2020 by Rahul Singh (682 points)  

I am creating swagger documentation for a Rest API. I want to write a test so that I can make sure that all the fields of the Model are annotated with @ApiModelProperty.

@ApiModel
public class Model {

  @ApiModelProperty(required = true)
  @NotBlank String name;

   @ApiModelProperty(required = true)
  @Positive Integer age;
}

What is the proper way to achieve this?

1 Answer

+1 vote
answered Nov 21, 2020 by Hitesh Garg (799 points)  
selected Nov 21, 2020 by Rahul Singh
 
Best answer

I have tried this once and then used the reflection to test whether some annotations are present or not on the fields.

There are possibilities to use some other Utils to get the classes and fields but in this example we are using pure java functionalities.

This test will also test all the fields of even all the nested classes of the Model class.

class ModelTest {
  private final Class<?> modelUnderTest = Model.class;
  private final List<Class<?>> allClasses = new ArrayList<>();

  private static boolean isStatic(int modifiers) {
    return Modifier.isStatic(modifiers);
  }

  private static boolean isNotStaticClass(Class<?> clazz) {
    return !isStatic(clazz.getModifiers());
  }

  @BeforeEach
  void setUp() {
    allClasses.add(modelUnderTest);
    Arrays.stream(modelUnderTest.getDeclaredClasses())
        // Skipping with Builder as in reality model was using the @lombok.Builder annotation 
        .filter(c -> !c.getName().contains("Builder"))
        .forEach(allClasses::add);
  }

  @Test
  void shouldBeAnnotatedWithApiModel() {
    Assert.assertTrue(modelUnderTest.isAnnotationPresent(ApiModel.class));
  }

  @Test
  void shouldHaveAllFieldsMarkedWithApiModelProperty() {
    forAllFields(
        field -> {
          if (!field.isAnnotationPresent(ApiModelProperty.class)) {
            Assert.fail("Annotation ApiModelPropertyAnnotation missing on " + field);
          } else {
            var annotation = field.getAnnotation(ApiModelProperty.class);
            assertThat(annotation.required()).isTrue();
          }
        });
  }

  @Test
  void stringsFieldsShouldBeMarkedWithNotBlank() {
    forAllFields(
        field -> {
          if (field.getType().equals(String.class)
              && !field.isAnnotationPresent(NotBlank.class)) {
            Assert.fail("Annotation NotBlank missing on " + field);
          }
        });
  }

  @Test
  void numbersFieldsShouldBeMarkedWithPositive() {
    forAllFields(
        field -> {
          if (field.getType().isAssignableFrom(Number.class)
              && !field.isAnnotationPresent(Positive.class)) {
            Assert.fail("Annotation Positive missing on " + field);
          }
        });
  }

  private void forAllFields(Consumer<Field> consumer) {
    for (var toTest : allClasses) {
      for (Field field : toTest.getDeclaredFields()) {
        if (isStatic(field.getModifiers())) {
          continue;
        }
        consumer.accept(field);
      }
    }
  }
}
...