Bei der Suche nach einer schnelleren Ausführungszeit für Komponententests im Spring Boot-Projekt habe ich herausgefunden, wie die Testausführung von benutzerdefinierten Validatoren, für die DI erforderlich ist, beschleunigt werden kann.
Manchmal möchte ich eine DB-Verbindung mit Bean Validation herstellen, z. B. beim Überprüfen der Eindeutigkeit eines Eingabewerts, und ich habe mit DI eine Reihe von benutzerdefinierten Validatoren wie folgt erstellt.
@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;
}
...
Wenn Sie jedoch einen Komponententest für einen solchen benutzerdefinierten Validator schreiben, müssen Sie den Validator mit den abhängigen Komponenten DI initialisieren. Ich habe also Tests mit @ SpringBootTest
geschrieben, aber die Spring-Initialisierung dauert lange und ich kann die Zunahme der Ausführungszeit nicht ertragen, wenn die Anzahl der benutzerdefinierten Validatoren zunimmt.
@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());
}
...
}
Durch Angabe des Attributs classes
der Annotation @ SpringBootTest
können Sie nur die erforderlichen Komponenten initialisieren und die Initialisierungszeit beim Teststart verkürzen.
- @SpringBootTest
+ @SpringBootTest(classes = {ValidationAutoConfiguration.class, EmployeeDao.class})
class EmployeeCodeUniqueValidatorTest {
@Autowired
private Validator validator;
@MockBean
private EmployeeDao employeeDao;
...
}
Nur als Referenz wurde es auf validatorbezogene Tests mit weniger als 30 Klassen und weniger als 500 Methoden angewendet, und die Ausführungszeit wurde auf weniger als die Hälfte reduziert: +1:
Die Testausführungszeit ist schneller, aber es ist ein Problem, dass Sie die Klassen jedes Mal in DI auflisten müssen. Während benutzerdefinierte Validator-Testklassen nur wenige DI-Komponenten enthalten, ist dies ziemlich gut, aber für Klassen mit vielen Abhängigkeiten ist es möglicherweise besser, die Wartbarkeit der Ausführungsgeschwindigkeit vorzuziehen.
Wenn Sie ein Team entwickeln, ist es außerdem schwierig, solche Implementierungsregeln zu vereinheitlichen, und es ist einfach, die Anzahl der Testcodes zu erhöhen, die ohne Ihr Wissen nur "@ SpringBootTest" angeben. Es scheint gut, ArchUnit usw. zu verwenden, um einen Mechanismus einzuführen, der mechanisch bemerkt.
@Test
void validatorTestShouldeRestrictAutowiredComponent() {
classes().that().haveNameMatching(".+ValidatorTest$").and().areAnnotatedWith(SpringBootTest.class)
.should()
.beAnnotatedWith(new DescribedPredicate<>("@SpringBootTest(classes = {ValidationAutoConfiguration.class, ...}Begrenzen Sie die Komponenten auf DI mit") {
@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);
}
In diesem Artikel habe ich Ihnen gezeigt, wie Sie den Komponententest von benutzerdefinierten Validatoren in einem Projekt mithilfe von Spring Boot beschleunigen können. Ich habe lange gewusst, dass die Testausführung von benutzerdefinierten Validatoren langsam ist, aber ich konnte diese Methode nicht leicht finden, indem ich im Internet suchte. Ich hoffe, dass sie für diejenigen hilfreich ist, die dieselben Probleme haben.
Recommended Posts