TNG / ArchUnit

A Java architecture test library, to specify and assert architecture rules in plain Java
http://archunit.org
Apache License 2.0
3.18k stars 287 forks source link

Enforce test failures based on the priority set #1337

Open arundotin opened 1 month ago

arundotin commented 1 month ago

Let's say that I have a rule this way

ArchRule rule = priority(Priority.LOW)
                .classes()
                .that()
                .resideInAPackage("com.example.utils")
                .should()
                .haveSimpleNameEndingWith("Util")
                .because("utility classes should have a 'Util' suffix");

        rule.check(classes);

I should be able to set somewhere that even if this rule is violated I should simply throw a warning, but not fail the test suite.

How do I do that ? There should be some native way to do this, as opposed to doing it via a huge method.

if there's no native way, I guess that could be prioritized :)

hankem commented 1 month ago
  1. I think that for ArchUnit's internal rules, rule.check(classes) currently always ends up in ArchRule.Assertions.check(rule, classes), which throws an AssertionError on failures, regardless of the priority , which should be available in the EvaluationResult and FailureReport.
  2. What can a test reasonably do on violations other than fail? Log the report and hope that somebody will read it? (Good luck!)

    • If you're willing to wrap all your rules manually, you could easily define an ArchRule decorator for such a behavior:

      public static ArchRule justLogFailuresOfPrioLowRules(ArchRule rule) {
          return new ArchRule() {
              @Override
              public void check(JavaClasses classes) {
                  EvaluationResult result = rule.evaluate(classes);
                  if (result.getPriority() != Priority.LOW) {
                      assertNoViolation(result);
                  } else {
                      FailureReport failureReport = result.getFailureReport();
                      if (!failureReport.isEmpty()) {
                          System.out.println(failureReport);
                      }
                  }
              }
      
              @Override
              public ArchRule because(String reason) {
                  return justLogFailuresOfPrioLowRules(rule.because(reason));
              }
      
              @Override
              public ArchRule allowEmptyShould(boolean allowEmptyShould) {
                  return justLogFailuresOfPrioLowRules(rule.allowEmptyShould(allowEmptyShould));
              }
      
              @Override
              public ArchRule as(String descirption) {
                  return justLogFailuresOfPrioLowRules(rule.as(descirption));
              }
      
              @Override
              public EvaluationResult evaluate(JavaClasses classes) {
                  return rule.evaluate(classes);
              }
      
              @Override
              public String getDescription() {
                  return rule.getDescription();
              }
          };
      }
    • If you want to automatically apply that behavior for every rule, you could probably look into a custom Junit TestEngine. FYI: For ArchUnit's JUnit 5 support, the rule evaluation happens in com.tngtech.archunit.junit.internal.ArchUnitTestDescriptor.ArchUnitRuleDescriptor.