Skip to content

Commit

Permalink
Provide a new JUnit 5 Rule checking test methods are using DisplayName
Browse files Browse the repository at this point in the history
Closes gh-29
  • Loading branch information
mnhock committed Jun 16, 2024
1 parent 6c461aa commit 0c890d0
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 41 deletions.
91 changes: 52 additions & 39 deletions docs/USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,44 +19,45 @@ Architecture rules are defined using Taikai's fluent API, allowing developers to

## 3. Usage

| Category | Subcategory | Method Name | Rule Description | Import Options |
|------------|----------------|--------------------------------------------------------|----------------------------------------------------------------------------------------------|-------------------------|
| **Java** | General | `classesShouldImplementHashCodeAndEquals` | Classes should implement `hashCode` and `equals` | Default (WITHOUT_TESTS) |
| | General | `fieldsShouldNotBePublic` | Fields should not be `public` (except constants) | Default (WITHOUT_TESTS) |
| | General | `methodsShouldNotThrowGenericException` | Methods should not throw generic exceptions (`Exception`, `RuntimeException`) | Default (WITHOUT_TESTS) |
| | General | `noUsageOf` | Disallow usage of specific classes | Default (WITHOUT_TESTS) |
| | General | `noUsageOf` | Disallow usage of specific classes by class reference | Default (WITHOUT_TESTS) |
| | General | `noUsageOfDeprecatedAPIs` | No usage of deprecated APIs annotated with `Deprecated` | Default (WITHOUT_TESTS) |
| | General | `noUsageOfSystemOutOrErr` | Disallow usage of `System.out` or `System.err` | Default (WITHOUT_TESTS) |
| | General | `utilityClassesShouldBeFinalAndHavePrivateConstructor` | Utility classes should be `final` and have a private constructor | Default (WITHOUT_TESTS) |
| | Imports | `shouldHaveNoCycles` | No cyclic dependencies in imports | Default (WITHOUT_TESTS) |
| | Imports | `shouldNotImport` | Disallow specific imports (e.g., `..shaded..`) | Default (WITHOUT_TESTS) |
| | Naming | `classesShouldNotMatch` | Classes should not match specific naming patterns (e.g., `.*Impl`) | Default (WITHOUT_TESTS) |
| | Naming | `methodsShouldNotMatch` | Methods should not match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `fieldsShouldNotMatch` | Fields should not match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `classesAnnotatedWithShouldMatch` | Classes annotated with should match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `methodsAnnotatedWithShouldMatch` | Methods annotated with should match specific naming patterns | Default (WITHOUT_TESTS) |
| | 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) |
| **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) |
| Category | Subcategory | Method Name | Rule Description | Import Options |
|------------|----------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|-------------------------|
| **Java** | General | `classesShouldImplementHashCodeAndEquals` | Classes should implement `hashCode` and `equals` | Default (WITHOUT_TESTS) |
| | General | `fieldsShouldNotBePublic` | Fields should not be `public` (except constants) | Default (WITHOUT_TESTS) |
| | General | `methodsShouldNotThrowGenericException` | Methods should not throw generic exceptions (`Exception`, `RuntimeException`) | Default (WITHOUT_TESTS) |
| | General | `noUsageOf` | Disallow usage of specific classes | Default (WITHOUT_TESTS) |
| | General | `noUsageOf` | Disallow usage of specific classes by class reference | Default (WITHOUT_TESTS) |
| | General | `noUsageOfDeprecatedAPIs` | No usage of deprecated APIs annotated with `Deprecated` | Default (WITHOUT_TESTS) |
| | General | `noUsageOfSystemOutOrErr` | Disallow usage of `System.out` or `System.err` | Default (WITHOUT_TESTS) |
| | General | `utilityClassesShouldBeFinalAndHavePrivateConstructor` | Utility classes should be `final` and have a private constructor | Default (WITHOUT_TESTS) |
| | Imports | `shouldHaveNoCycles` | No cyclic dependencies in imports | Default (WITHOUT_TESTS) |
| | Imports | `shouldNotImport` | Disallow specific imports (e.g., `..shaded..`) | Default (WITHOUT_TESTS) |
| | Naming | `classesShouldNotMatch` | Classes should not match specific naming patterns (e.g., `.*Impl`) | Default (WITHOUT_TESTS) |
| | Naming | `methodsShouldNotMatch` | Methods should not match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `fieldsShouldNotMatch` | Fields should not match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `classesAnnotatedWithShouldMatch` | Classes annotated with should match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `methodsAnnotatedWithShouldMatch` | Methods annotated with should match specific naming patterns | Default (WITHOUT_TESTS) |
| | 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) |
| **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) |

### Java Configuration

Expand Down Expand Up @@ -207,7 +208,19 @@ Taikai.builder()
.namespace("com.company.yourproject")
.test(test -> test
.junit5(junit5 -> junit5
.methodsShouldBePackagePrivate()))
.methodsShouldBePackagePrivate()))
.build()
.check();
```

- **Ensure Test Methods are Annotated with `@DisplayName`**: Enforce that JUnit 5 test methods annotated with `@Test` or `@ParameterizedTest` are also annotated with `@DisplayName` to provide descriptive test names.

```java
Taikai.builder()
.namespace("com.company.yourproject")
.test(test -> test
.junit5(junit5 -> junit5
.methodsShouldBeAnnotatedWithDisplayName()))
.build()
.check();
```
Expand Down
17 changes: 15 additions & 2 deletions src/main/java/com/enofex/taikai/test/JUnit5Configurer.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.enofex.taikai.test;

import static com.enofex.taikai.test.JUnit5Predicates.ANNOTATION_DISABLED;
import static com.enofex.taikai.test.JUnit5Predicates.ANNOTATION_DISPLAY_NAME;
import static com.enofex.taikai.test.JUnit5Predicates.ANNOTATION_PARAMETRIZED_TEST;
import static com.enofex.taikai.test.JUnit5Predicates.ANNOTATION_TEST;
import static com.enofex.taikai.test.JUnit5Predicates.annotatedWithTestOrParameterizedTest;
Expand All @@ -16,12 +18,23 @@

public final class JUnit5Configurer extends AbstractConfigurer {

private static final String ANNOTATION_DISABLED = "org.junit.jupiter.api.Disabled";

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

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

public JUnit5Configurer methodsShouldBeAnnotatedWithDisplayName(Configuration configuration) {
return addRule(TaikaiRule.of(methods()
.that(are(annotatedWithTestOrParameterizedTest(true)))
.should().beMetaAnnotatedWith(ANNOTATION_DISPLAY_NAME)
.as("Methods annotated with %s or %s should be annotated with %s".formatted(ANNOTATION_TEST,
ANNOTATION_PARAMETRIZED_TEST, ANNOTATION_DISPLAY_NAME)),
configuration));
}

public JUnit5Configurer methodsShouldBePackagePrivate() {
return methodsShouldBePackagePrivate(Configuration.of(Namespace.IMPORT.WITH_TESTS));
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/enofex/taikai/test/JUnit5Predicates.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ final class JUnit5Predicates {

static final String ANNOTATION_TEST = "org.junit.jupiter.api.Test";
static final String ANNOTATION_PARAMETRIZED_TEST = "org.junit.jupiter.params.ParameterizedTest";
static final String ANNOTATION_DISABLED = "org.junit.jupiter.api.Disabled";
static final String ANNOTATION_DISPLAY_NAME = "org.junit.jupiter.api.DisplayName";


private JUnit5Predicates() {
}
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 @@ -32,6 +32,7 @@ public static void main(String[] args) {
.test(test -> test
.junit5(junit5 -> junit5
.methodsShouldBePackagePrivate()
.methodsShouldBeAnnotatedWithDisplayName()
.classesShouldNotBeAnnotatedWithDisabled()
.methodsShouldNotBeAnnotatedWithDisabled()))
.java(java -> java
Expand Down

0 comments on commit 0c890d0

Please sign in to comment.