Как мне создать правило ArchUnit для проверки того, что все генерируемые исключения наследуются от определенного пользовательского исключения?

#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))) .