Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a new JUnit 5 Rule checking if the test methods do not declar… #39

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 33 additions & 20 deletions docs/USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,27 @@ Architecture rules are defined using Taikai's fluent API, allowing developers to
| | Naming | `fieldsAnnotatedWithShouldMatch` | Fields annotated with should match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `constantsShouldFollowConvention` | Constants should follow naming conventions | Default (WITHOUT_TESTS) |
| | Naming | `interfacesShouldNotHavePrefixI` | Interfaces should not have the prefix `I` | Default (WITHOUT_TESTS) |
| **Test** | JUnit 5 | `classesShouldNotBeAnnotatedWithDisabled` | Ensure classes are not annotated with `@Disabled` | Default (WITH_TESTS) |
| | JUnit 5 | `methodsShouldNotBeAnnotatedWithDisabled` | Ensure methods are not annotated with `@Disabled` | Default (WITH_TESTS) |
| | JUnit 5 | `methodsShouldBePackagePrivate` | Ensure that test methods annotated with `@Test` or `@ParameterizedTest` are package-private. | Default (WITH_TESTS) |
| | JUnit 5 | `methodsShouldBeAnnotatedWithDisplayName` | Ensure that test methods annotated with `@Test` or `@ParameterizedTest` are annotated with `@DisplayName`. | Default (WITH_TESTS) |
| | JUnit 5 | `methodsShouldMatch` | Ensure that test methods annotated with `@Test` or `@ParameterizedTest` have names matching a specific regex pattern. | Default (WITH_TESTS) |
| **Spring** | General | `noAutowiredFields` | Fields should not be annotated with `@Autowired` (prefer constructor injection) | Default (WITH_TESTS) |
| | Boot | `springBootApplicationShouldBeIn` | Ensure `@SpringBootApplication` is in the default package | Default (WITH_TESTS) |
| | Configurations | `namesShouldEndWithConfiguration` | Configuration classes should end with "Configuration" | Default (WITH_TESTS) |
| | Configurations | `namesShouldMatch` | Configuration classes should match a regex pattern | Default (WITH_TESTS) |
| | Controllers | `namesShouldEndWithController` | Controllers should end with "Controller" | Default (WITH_TESTS) |
| | Controllers | `namesShouldMatch` | Controllers should match a regex pattern | Default (WITH_TESTS) |
| | Controllers | `shouldBeAnnotatedWithRestController` | Controllers should be annotated with `@RestController` | Default (WITH_TESTS) |
| | Controllers | `shouldBePackagePrivate` | Controllers should be package-private | Default (WITH_TESTS) |
| | Controllers | `shouldNotDependOnOtherControllers` | Controllers should not depend on other controllers | Default (WITH_TESTS) |
| | Repositories | `namesShouldEndWithRepository` | Repositories should end with "Repository" | Default (WITH_TESTS) |
| | Repositories | `namesShouldMatch` | Repositories should match a regex pattern | Default (WITH_TESTS) |
| | Repositories | `shouldBeAnnotatedWithRepository` | Repositories should be annotated with `@Repository` | Default (WITH_TESTS) |
| | Services | `namesShouldEndWithService` | Services should end with "Service" | Default (WITH_TESTS) |
| | Services | `namesShouldMatch` | Services should match a regex pattern | Default (WITH_TESTS) |
| | Services | `shouldBeAnnotatedWithService` | Services should be annotated with `@Service` | Default (WITH_TESTS) |
| **Test** | JUnit 5 | `classesShouldNotBeAnnotatedWithDisabled` | Ensure classes are not annotated with `@Disabled` | Default (ONLY_TESTS) |
| | JUnit 5 | `methodsShouldNotBeAnnotatedWithDisabled` | Ensure methods are not annotated with `@Disabled` | Default (ONLY_TESTS) |
| | JUnit 5 | `methodsShouldBePackagePrivate` | Ensure that test methods annotated with `@Test` or `@ParameterizedTest` are package-private. | Default (ONLY_TESTS) |
| | JUnit 5 | `methodsShouldBeAnnotatedWithDisplayName` | Ensure that test methods annotated with `@Test` or `@ParameterizedTest` are annotated with `@DisplayName`. | Default (ONLY_TESTS) |
| | JUnit 5 | `methodsShouldMatch` | Ensure that test methods annotated with `@Test` or `@ParameterizedTest` have names matching a specific regex pattern. | Default (ONLY_TESTS) |
| | JUnit 5 | `methodsShouldNotDeclareThrownExceptions` | Ensure that test methods annotated with `@Test` or `@ParameterizedTest` do not declare any thrown exceptions. | Default (ONLY_TESTS) |
| **Spring** | General | `noAutowiredFields` | Fields should not be annotated with `@Autowired` (prefer constructor injection) | Default (WITHOUT_TESTS) |
| | Boot | `springBootApplicationShouldBeIn` | Ensure `@SpringBootApplication` is in the default package | Default (WITHOUT_TESTS) |
| | Configurations | `namesShouldEndWithConfiguration` | Configuration classes should end with "Configuration" | Default (WITHOUT_TESTS) |
| | Configurations | `namesShouldMatch` | Configuration classes should match a regex pattern | Default (WITHOUT_TESTS) |
| | Controllers | `namesShouldEndWithController` | Controllers should end with "Controller" | Default (WITHOUT_TESTS) |
| | Controllers | `namesShouldMatch` | Controllers should match a regex pattern | Default (WITHOUT_TESTS) |
| | Controllers | `shouldBeAnnotatedWithRestController` | Controllers should be annotated with `@RestController` | Default (WITHOUT_TESTS) |
| | Controllers | `shouldBePackagePrivate` | Controllers should be package-private | Default (WITHOUT_TESTS) |
| | Controllers | `shouldNotDependOnOtherControllers` | Controllers should not depend on other controllers | Default (WITHOUT_TESTS) |
| | Repositories | `namesShouldEndWithRepository` | Repositories should end with "Repository" | Default (WITHOUT_TESTS) |
| | Repositories | `namesShouldMatch` | Repositories should match a regex pattern | Default (WITHOUT_TESTS) |
| | Repositories | `shouldBeAnnotatedWithRepository` | Repositories should be annotated with `@Repository` | Default (WITHOUT_TESTS) |
| | Services | `namesShouldEndWithService` | Services should end with "Service" | Default (WITHOUT_TESTS) |
| | Services | `namesShouldMatch` | Services should match a regex pattern | Default (WITHOUT_TESTS) |
| | Services | `shouldBeAnnotatedWithService` | Services should be annotated with `@Service` | Default (WITHOUT_TESTS) |

### Java Configuration

Expand Down Expand Up @@ -238,6 +239,18 @@ Taikai.builder()
.check();
```

- **Ensure Test Methods Do Not Declare Thrown Exceptions** Ensure that JUnit 5 test methods annotated with `@Test` or `@ParameterizedTest` do not declare any thrown exceptions.

```java
Taikai.builder()
.namespace("com.company.yourproject")
.test(test -> test
.junit5(junit5 -> junit5
.methodsShouldNotDeclareThrownExceptions()))
.build()
.check();
```

### Spring Configuration

Spring configuration involves defining constraints specific to Spring Framework usage.
Expand Down
44 changes: 38 additions & 6 deletions src/main/java/com/enofex/taikai/test/JUnit5Configurer.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,26 @@
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noMethods;

import com.enofex.taikai.Namespace;
import com.enofex.taikai.Namespace.IMPORT;
import com.enofex.taikai.TaikaiRule;
import com.enofex.taikai.TaikaiRule.Configuration;
import com.enofex.taikai.configures.AbstractConfigurer;
import com.enofex.taikai.configures.ConfigurerContext;
import com.tngtech.archunit.core.domain.JavaMethod;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;

public final class JUnit5Configurer extends AbstractConfigurer {

private static final Configuration CONFIGURATION = Configuration.of(IMPORT.ONLY_TESTS);

JUnit5Configurer(ConfigurerContext configurerContext) {
super(configurerContext);
}

public JUnit5Configurer methodsShouldMatch(String regex) {
return methodsShouldMatch(regex, null);
return methodsShouldMatch(regex, CONFIGURATION);
}

public JUnit5Configurer methodsShouldMatch(String regex, Configuration configuration) {
Expand All @@ -35,8 +41,21 @@ public JUnit5Configurer methodsShouldMatch(String regex, Configuration configura
configuration));
}

public JUnit5Configurer methodsShouldNotDeclareThrownExceptions() {
return methodsShouldNotDeclareThrownExceptions(CONFIGURATION);
}

public JUnit5Configurer methodsShouldNotDeclareThrownExceptions(Configuration configuration) {
return addRule(TaikaiRule.of(methods()
.that(are(annotatedWithTestOrParameterizedTest(true)))
.should(notDeclareThrownExceptions())
.as("Methods annotated with %s or %s should not declare thrown Exceptions".formatted(
ANNOTATION_TEST, ANNOTATION_PARAMETRIZED_TEST)),
configuration));
}

public JUnit5Configurer methodsShouldBeAnnotatedWithDisplayName() {
return methodsShouldBeAnnotatedWithDisplayName(Configuration.of(Namespace.IMPORT.WITH_TESTS));
return methodsShouldBeAnnotatedWithDisplayName(CONFIGURATION);
}

public JUnit5Configurer methodsShouldBeAnnotatedWithDisplayName(Configuration configuration) {
Expand All @@ -49,7 +68,7 @@ public JUnit5Configurer methodsShouldBeAnnotatedWithDisplayName(Configuration co
}

public JUnit5Configurer methodsShouldBePackagePrivate() {
return methodsShouldBePackagePrivate(Configuration.of(Namespace.IMPORT.WITH_TESTS));
return methodsShouldBePackagePrivate(CONFIGURATION);
}

public JUnit5Configurer methodsShouldBePackagePrivate(Configuration configuration) {
Expand All @@ -62,7 +81,7 @@ public JUnit5Configurer methodsShouldBePackagePrivate(Configuration configuratio
}

public JUnit5Configurer methodsShouldNotBeAnnotatedWithDisabled() {
return methodsShouldNotBeAnnotatedWithDisabled(Configuration.of(Namespace.IMPORT.WITH_TESTS));
return methodsShouldNotBeAnnotatedWithDisabled(CONFIGURATION);
}

public JUnit5Configurer methodsShouldNotBeAnnotatedWithDisabled(Configuration configuration) {
Expand All @@ -73,7 +92,7 @@ public JUnit5Configurer methodsShouldNotBeAnnotatedWithDisabled(Configuration co
}

public JUnit5Configurer classesShouldNotBeAnnotatedWithDisabled() {
return classesShouldNotBeAnnotatedWithDisabled(Configuration.of(Namespace.IMPORT.WITH_TESTS));
return classesShouldNotBeAnnotatedWithDisabled(CONFIGURATION);
}

public JUnit5Configurer classesShouldNotBeAnnotatedWithDisabled(Configuration configuration) {
Expand All @@ -82,4 +101,17 @@ public JUnit5Configurer classesShouldNotBeAnnotatedWithDisabled(Configuration co
.as("Classes should not be annotated with %s".formatted(ANNOTATION_DISABLED)),
configuration));
}

private ArchCondition<JavaMethod> notDeclareThrownExceptions() {
return new ArchCondition<>("not declare thrown exceptions") {
@Override
public void check(JavaMethod method, ConditionEvents events) {
if (!method.getThrowsClause().isEmpty()) {
String message = String.format("Method %s declares thrown exceptions",
method.getFullName());
events.add(SimpleConditionEvent.violated(method, message));
}
}
};
}
}
1 change: 1 addition & 0 deletions src/test/java/com/enofex/taikai/ArchitectureTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ void shouldFulfilConstrains() {
.namespace("com.enofex.taikai")
.test(test -> test
.junit5(junit5 -> junit5
.methodsShouldNotDeclareThrownExceptions()
.methodsShouldMatch("should.*")
.methodsShouldBePackagePrivate()
.classesShouldNotBeAnnotatedWithDisabled()
Expand Down
1 change: 1 addition & 0 deletions src/test/java/com/enofex/taikai/Usage.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public static void main(String[] args) {
.namesShouldEndWithRepository()))
.test(test -> test
.junit5(junit5 -> junit5
.methodsShouldNotDeclareThrownExceptions()
.methodsShouldMatch("should.*")
.methodsShouldBePackagePrivate()
.methodsShouldBeAnnotatedWithDisplayName()
Expand Down
Loading