#java #unit-testing #archunit
#java #модульное тестирование #archunit
Вопрос:
Одно из моих правил архитектуры заключается в том, что все исключения, генерируемые кодом приложения, должны быть либо CustomException, либо подклассом CustomException.
У меня возникли трудности с написанием этого правила в ArchUnit. В настоящее время у меня есть следующее:
private static final ArchCondition<JavaClass> THROWS_NON_CUSTOM_EXCEPTION = callCodeUnitWhere(
target(is(constructor()))
.and(
originOwner(
is(assignableTo(Throwable.class))
.and(not(assignableTo(CustomException.class)))
)
)
);
@ArchTest public static final ArchRule noNonCustomExceptions = noClasses()
.should(THROWS_NON_CUSTOM_EXCEPTION);
Выполнение этого правила возвращает true (тест JUnit пройден), даже если у меня есть код, который выдает исключение, которое также не является CustomException.
Я протестировал часть правила, которая определяет, что у конструктора есть владелец, который может быть назначен для Throwable:
private static final ArchCondition<JavaClass> THROWS_NON_CUSTOM_EXCEPTION =
callCodeUnitWhere(
target(is(constructor()))
.and(
originOwner(
is(assignableTo(Throwable.class))
)
)
);
Это корректно возвращает каждое место в коде, которое создает любой Throwable.
Проблема, похоже, в моем коде, который пытается найти владельцев, которые НЕ могут быть назначены CustomException:
private static final ArchCondition<JavaClass> THROWS_NON_CUSTOM_EXCEPTION = callCodeUnitWhere(
target(is(constructor()))
.and(
originOwner(
is(not(assignableTo(CustomException.class)))
)
)
);
Это возвращает каждый конструктор, даже те для исключений, которые можно назначить CustomException .
Как правильно в ArchUnit написать правило, которое возвращает каждую единицу кода, вызывающую конструктор, владелец которого может быть назначен Throwable и не может быть назначен CustomException?
Ответ №1:
Я думаю, вам просто нужно объединить части, которые у вас уже есть. Следующий код работает для меня:
noClasses().should().callCodeUnitWhere(
JavaCall.Predicates.target(
AccessTarget.Predicates.constructor()
.and(AccessTarget.Predicates.declaredIn(JavaClass.Predicates.assignableTo(Throwable.class)))
.and(DescribedPredicate.not(AccessTarget.Predicates.declaredIn(JavaClass.Predicates.assignableTo(BaseException.class))))
)
);
Если ваш BaseException
находится в анализируемой области, вам нужно будет исключить этот класс: noClasses().that(not(belongToAnyOf(BaseException.class)))
.