archunit_使用ArchUnit验证代码和体系结构约束

ArchUnit是一个Java库,用于根据自定义代码和架构约束检查代码。本文介绍了如何创建和应用ArchUnit规则,如验证类依赖、分层架构、通用规则,并提供了实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

archunit

archunit

介绍

ArchUnit是一个用于根据一组自定义代码和体系结构约束检查Java代码的库。 这些约束可以在单元测试中的流畅Java API中定义。 ArchUnit可用于验证类或层之间的依赖关系,检查循环依赖关系等等。 在本文中,我们将创建一些示例规则,以了解如何从ArchUnit中受益。

必需的依赖

要使用ArchUnit,我们需要在项目中添加以下依赖项:

 < dependency >

    < groupId >com.tngtech.archunit</ groupId >

    < artifactId >archunit-junit5</ artifactId >

    < version >0.13.0</ version >

    < scope >test</ scope >
 </ dependency >

如果您仍在使用JUnit 4,则应改用archunit-junit4构件。

创建第一个ArchUnit规则

现在,我们可以开始创建第一个ArchUnit规则。 为此,我们在测试文件夹中创建一个新类:

 @RunWith (ArchUnitRunner. class ) //only for JUnit 4, not needed with JUnit 5
 @AnalyzeClasses (packages = "com.mscharhag.archunit" )
 public class ArchUnitTest { 
    // verify that classes whose name name ends with "Service" should be located in a "service" package

    @ArchTest

    private final ArchRule services_are_located_in_service_package = classes()

            .that().haveSimpleNameEndingWith( "Service" )

            .should().resideInAPackage( "..service" );
 }

通过@AnalyzeClasses,我们告诉ArchUnit应该分析哪些Java软件包。 如果使用的是JUnit 4,则还需要添加ArchUnit JUnit运行器。

在类内部,我们创建一个字段并使用@ArchTest对其进行注释。 这是我们的第一个测试。

我们可以使用ArchUnits流畅的Java API定义要验证的约束。 在此示例中,我们要验证所有名称以Service结尾的类(例如UserService )是否位于名为service (例如foo.bar.service )的包中。

大多数ArchUnit规则都以选择器开头,该选择器指示应验证哪种类型的代码单元(类,方法,字段等)。 在这里,我们使用静态方法classes()选择类。 我们使用that()方法将选择范围限制为类的子集(此处,我们仅选择名称以Service结尾的类)。 使用should()方法,我们可以定义与所选类匹配的约束(此处:这些类应位于服务包中)。

运行此测试类时,将执行所有带有@ArchTest注释的测试。 如果ArchUnits在服务包之外检测到服务类,则测试将失败。

更多例子

让我们看看更多示例。

我们可以使用ArchUnit来确保所有Logger字段都是私有,静态和最终的:

 // verify that logger fields are private, static and final
 @ArchTest
 private final ArchRule loggers_should_be_private_static_final = fields()

        .that().haveRawType(Logger. class )

        .should().bePrivate()

        .andShould().beStatic()

        .andShould().beFinal();

在这里,我们选择Logger类型的字段,并在一条规则中定义多个约束。

或者我们可以确保实用程序类中的方法必须是静态的:

 // methods in classes whose name ends with "Util" should be static
 @ArchTest
 static final ArchRule utility_methods_should_be_static = methods()

        .that().areDeclaredInClassesThat().haveSimpleNameEndingWith( "Util" )

        .should().beStatic();

要强制名为impl的软件包不包含任何接口,我们可以使用以下规则:

 // verify that interfaces are not located in implementation packages
 @ArchTest
 static final ArchRule interfaces_should_not_be_placed_in_impl_packages = noClasses()

        .that().resideInAPackage( "..impl.." )

        .should().beInterfaces();

请注意,我们使用noClasses()而不是classes()来抵消should约束。

(我个人认为,如果我们可以将规则定义为interfaces()。should()。notResideInAPackage(“ .. impl ..”),则该规则将更容易阅读。不幸的是,ArchUnit不提供interfaces()方法)

也许我们正在使用Java Persistence API,并希望确保EntityManager仅在存储库类中使用:

 @ArchTest
 static final ArchRule only_repositories_should_use_entityManager = noClasses()

        .that().resideOutsideOfPackage( "..repository" )

        .should().dependOnClassesThat().areAssignableTo(EntityManager. class );

分层架构示例

ArchUnit还附带了一些实用程序,用于验证特定的体系结构样式。

例如,我们可以使用layeredArchitecture()来验证分层体系结构中各层的访问规则:

 @ArchTest
 static final ArchRule layer_dependencies_are_respected = layeredArchitecture()

        .layer( "Controllers" ).definedBy( "com.mscharhag.archunit.layers.controller.." )

        .layer( "Services" ).definedBy( "com.mscharhag.archunit.layers.service.." )

        .layer( "Repositories" ).definedBy( "com.mscharhag.archunit.layers.repository.." )

        .whereLayer( "Controllers" ).mayNotBeAccessedByAnyLayer()

        .whereLayer( "Services" ).mayOnlyBeAccessedByLayers( "Controllers" )

        .whereLayer( "Repositories" ).mayOnlyBeAccessedByLayers( "Services" );

在这里,我们定义了三层:控制器,服务和存储库。 存储库层只能由服务层访问,而服务层只能由控制器访问。

通用规则的快捷方式

为了避免我们必须自己定义所有规则,ArchUnit附带了一组定义为静态常量的通用规则。 如果这些规则符合我们的需求,我们可以简单地将它们分配给测试中的@ArchTest字段。

例如,如果我们确保没有抛出Exception和RuntimeException类型的异常,则可以使用预定义的NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS规则:

 @ArchTest
 private final ArchRule no_generic_exceptions = NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS;

概要

ArchUnit是一个强大的工具,可以根据一组自定义规则来验证代码库。 常见的静态代码分析工具(例如FindBugs或SonarQube)也报告了我们看到的一些示例。 但是,这些工具通常很难用您自己的项目特定规则进行扩展,这就是ArchUnit的用武之地。

与往常一样,您可以从GitHub上的示例中找到Sources。 如果您对ArchUnit感兴趣,还应该查看全面的用户指南

翻译自: https://www.javacodegeeks.com/2020/02/validating-code-and-architecture-constraints-with-archunit.html

archunit

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值