Tout en explorant des temps d'exécution plus rapides des tests unitaires dans le projet Spring Boot, j'ai découvert comment accélérer l'exécution des tests de validateurs personnalisés qui nécessitent une DI.
Parfois, je souhaite établir une connexion DB avec Bean Validation, par exemple lors de la vérification de l'unicité d'une valeur d'entrée, et j'ai créé un certain nombre de validateurs personnalisés à l'aide de DI comme suit.
@Documented
@Constraint(validatedBy = { EmployeeCodeUniqueValidator.class })
@Target({ TYPE })
@Retention(RUNTIME)
public @interface EmployeeCodeUniqueConstraint {
...
}
public class EmployeeCodeUniqueValidator implements ConstraintValidator<EmployeeCodeUniqueConstraint, Object> {
private static final String EMPLOYEE_ID = "id";
private static final String EMPLOYEE_CODE = "employeeCode";
private final EmployeeDao employeeDao;
public EmployeeCodeUniqueValidator(final EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
String employeeCode = getField(value, EMPLOYEE_CODE);
if (employeeCode == null) {
return true;
}
Optional<Employee> employeeOpt = employeeDao.findByEmployeeCode(employeeCode);
if (employeeOpt.isEmpty()) {
return true;
}
...
Cependant, lors de l'écriture d'un test unitaire pour un tel validateur personnalisé, vous devez initialiser le validateur avec les composants dépendants DI. En conséquence, j'ai écrit des tests en utilisant @ SpringBootTest
, mais l'initialisation Spring prend beaucoup de temps et je ne supporte pas l'augmentation du temps d'exécution à mesure que le nombre de validateurs personnalisés augmente.
@SpringBootTest
class EmployeeCodeUniqueValidatorTest {
@Autowired
private Validator validator;
@MockBean
private EmployeeDao employeeDao;
@EmployeeCodeUniqueConstraint
class Form {
public String id;
public String employeeCode;
}
@Test
void newEmployeeCode() {
when(employeeDao.findByEmployeeCode("012345")).thenReturn(Optional.empty());
Form form = new Form();
form.employeeCode = "012345";
assertTrue(validator.validate(form).isEmpty());
}
...
}
En spécifiant l'attribut classes
de l'annotation @ SpringBootTest
, vous pouvez initialiser uniquement les composants nécessaires et réduire le temps d'initialisation au démarrage du test.
- @SpringBootTest
+ @SpringBootTest(classes = {ValidationAutoConfiguration.class, EmployeeDao.class})
class EmployeeCodeUniqueValidatorTest {
@Autowired
private Validator validator;
@MockBean
private EmployeeDao employeeDao;
...
}
Pour référence seulement, il a été appliqué aux tests liés au validateur avec moins de 30 classes et moins de 500 méthodes, et le temps d'exécution a été réduit à moins de la moitié: +1:
Le temps d'exécution du test sera plus rapide, mais c'est un problème que vous devez à chaque fois énumérer les classes à DI. La classe de test du validateur personnalisé a peu de composants DI, ce qui est plutôt bien, mais dans une classe avec de nombreuses dépendances, il peut être préférable de donner la priorité à la maintenabilité par rapport à la vitesse d'exécution.
De plus, si vous développez une équipe, il est difficile d'unifier de telles règles d'implémentation, et il est facile d'augmenter le nombre de codes de test qui spécifient uniquement @ SpringBootTest
à votre insu. Il semble bon d'utiliser ArchUnit etc. pour introduire un mécanisme de notification mécanique.
@Test
void validatorTestShouldeRestrictAutowiredComponent() {
classes().that().haveNameMatching(".+ValidatorTest$").and().areAnnotatedWith(SpringBootTest.class)
.should()
.beAnnotatedWith(new DescribedPredicate<>("@SpringBootTest(classes = {ValidationAutoConfiguration.class, ...}Limiter les composants à DI avec") {
@Override
public boolean apply(JavaAnnotation annot) {
if (!annot.getRawType().getSimpleName().equals("SpringBootTest")) {
return true;
}
JavaClass[] classes = (JavaClass[]) annot.get("classes").or(new JavaClass[]{});
return Arrays.stream(classes)
.anyMatch(clazz -> clazz.getSimpleName().equals("ValidationAutoConfiguration"));
}
})
.check(ALL_CLASSES);
}
Dans cet article, je vous ai montré comment accélérer les tests unitaires des validateurs personnalisés dans un projet à l'aide de Spring Boot. Je sais depuis longtemps que l'exécution des tests des validateurs personnalisés est lente, mais je n'ai pas pu trouver cette méthode facilement en recherchant sur le net, donc j'espère qu'elle sera utile pour ceux qui ont les mêmes problèmes.
Recommended Posts