<commit_before>== JUnit Support

At the moment ArchUnit offers extended support for writing tests with JUnit 4 and JUnit 5.
This mainly tackles the problem of caching classes between test runs and to remove some boilerplate.

Consider a straight forward approach to write tests:

[source,java,options="nowrap"]
----
@Test
public void rule1() {
    JavaClasses importedClasses = new ClassFileImporter().importClasspath();

    ArchRule rule = classes()...

    rule.check(importedClasses);
}

@Test
public void rule2() {
    JavaClasses importedClasses = new ClassFileImporter().importClasspath();

    ArchRule rule = classes()...

    rule.check(importedClasses);
}
----

For bigger projects, this will have a significant performance impact, since the import can take
a noticeable amount of time. Also rules will always be checked against the imported classes, thus
the explicit call of `check(importedClasses)` is bloat and error prone (i.e. it can be forgotten).

=== JUnit 4 & 5 Support

Make sure you follow the installation instructions at <<Installation>>, in particular to include
the correct dependency for the respective JUnit support.

==== Writing tests

Tests look and behave very similar between JUnit 4 and 5. The only difference is, that with JUnit 4
it is necessary to add a specific `Runner` to take care of caching and checking rules, while JUnit 5
picks up the respective `TestEngine` transparently. A test typically looks the following way:

[source,java,options="nowrap"]
----
@RunWith(ArchUnitRunner.class) // Remove this line for JUnit 5!!
@AnalyzeClasses(packages = "com.myapp")
public class ArchitectureTest {

    // ArchRules can just be declared as static fields and will be evaluated
    @ArchTest
    public static final ArchRule rule1 = classes().should()...

    @ArchTest
    public static final ArchRule rule2 = classes().should()...

    @ArchTest
    public static void rule3(JavaClasses classes) {
        // The runner also understands static methods with a single JavaClasses argument
        // reusing the cached classes
    }

}
----

The `JavaClass` cache will work in two ways. On the one hand it will cache the classes by test,
so they can be reused by several rules declared within the same class. On the other hand, it
will cache the classes by location, so a second test that wants to import classes from the same
URLs will reuse the classes previously imported as well. Note that this second caching uses
soft references, so the classes will be dropped from memory, if the heap runs low.
For further information see <<Controlling the Cache>>.

==== Controlling the Import

Which classes will be imported can be controlled in a declarative way through `@AnalyzeClasses`.
If no packages or locations are provided, the whole classpath will be imported.
You can specify packages to import as strings:

[source,java,options="nowrap"]
----
@AnalyzeClasses(packages = {"com.myapp.subone", "com.myapp.subone"})
----

To better support refactorings, packages can also be declared relative to classes, i.e. the
packages these classes reside in will be imported:

[source,java,options="nowrap"]
----
@AnalyzeClasses(packagesOf = {SubOneConfiguration.class, SubTwoConfiguration.class})
----

As a third option, locations can be specified freely by implementing a `LocationProvider`:

[source,java,options="nowrap"]
----
public class MyLocationProvider implements LocationProvider {
    @Override
    public Set<Location> get(Class<?> testClass) {
        // Determine Locations (= URLs) to import
        // Can also consider the actual test class, e.g. to read some custom annotation
    }
}

@AnalyzeClasses(locations = MyLocationProvider.class)<commit_msg>correct same package being imported in the user guide example #584<commit_after>== JUnit Support

At the moment ArchUnit offers extended support for writing tests with JUnit 4 and JUnit 5.
This mainly tackles the problem of caching classes between test runs and to remove some boilerplate.

Consider a straight forward approach to write tests:

[source,java,options="nowrap"]
----
@Test
public void rule1() {
    JavaClasses importedClasses = new ClassFileImporter().importClasspath();

    ArchRule rule = classes()...

    rule.check(importedClasses);
}

@Test
public void rule2() {
    JavaClasses importedClasses = new ClassFileImporter().importClasspath();

    ArchRule rule = classes()...

    rule.check(importedClasses);
}
----

For bigger projects, this will have a significant performance impact, since the import can take
a noticeable amount of time. Also rules will always be checked against the imported classes, thus
the explicit call of `check(importedClasses)` is bloat and error prone (i.e. it can be forgotten).

=== JUnit 4 & 5 Support

Make sure you follow the installation instructions at <<Installation>>, in particular to include
the correct dependency for the respective JUnit support.

==== Writing tests

Tests look and behave very similar between JUnit 4 and 5. The only difference is, that with JUnit 4
it is necessary to add a specific `Runner` to take care of caching and checking rules, while JUnit 5
picks up the respective `TestEngine` transparently. A test typically looks the following way:

[source,java,options="nowrap"]
----
@RunWith(ArchUnitRunner.class) // Remove this line for JUnit 5!!
@AnalyzeClasses(packages = "com.myapp")
public class ArchitectureTest {

    // ArchRules can just be declared as static fields and will be evaluated
    @ArchTest
    public static final ArchRule rule1 = classes().should()...

    @ArchTest
    public static final ArchRule rule2 = classes().should()...

    @ArchTest
    public static void rule3(JavaClasses classes) {
        // The runner also understands static methods with a single JavaClasses argument
        // reusing the cached classes
    }

}
----

The `JavaClass` cache will work in two ways. On the one hand it will cache the classes by test,
so they can be reused by several rules declared within the same class. On the other hand, it
will cache the classes by location, so a second test that wants to import classes from the same
URLs will reuse the classes previously imported as well. Note that this second caching uses
soft references, so the classes will be dropped from memory, if the heap runs low.
For further information see <<Controlling the Cache>>.

==== Controlling the Import

Which classes will be imported can be controlled in a declarative way through `@AnalyzeClasses`.
If no packages or locations are provided, the whole classpath will be imported.
You can specify packages to import as strings:

[source,java,options="nowrap"]
----
@AnalyzeClasses(packages = {"com.myapp.subone", "com.myapp.subtwo"})
----

To better support refactorings, packages can also be declared relative to classes, i.e. the
packages these classes reside in will be imported:

[source,java,options="nowrap"]
----
@AnalyzeClasses(packagesOf = {SubOneConfiguration.class, SubTwoConfiguration.class})
----

As a third option, locations can be specified freely by implementing a `LocationProvider`:

[source,java,options="nowrap"]
----
public class MyLocationProvider implements LocationProvider {
    @Override
    public Set<Location> get(Class<?> testClass) {
        // Determine Locations (= URLs) to import
        // Can also consider the actual test class, e.g. to read some custom annotation
    }
}

@AnalyzeClasses(locations = MyLocationProvider.class)
{'fraction_non_alphanumeric': 0.07909225191352222, 'fraction_numerical': 0.004162750100711696, 'mean_word_length': 4.140096618357488, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7470755', 'n_tokens_mistral': 1916, 'n_tokens_neox': 1845, 'n_words': 921}