如何为代码设计创建单元测试?

2025-06-10

如何为代码设计创建单元测试?

预览图片

作为一名经验丰富的软件工程师,我深知精心设计的代码的重要性,以及单元测试在维护代码完整性方面所发挥的作用。代码设计是任何软件系统的基础。它是指导系统构建的蓝图,确保最终产品的健壮性、可扩展性和可维护性。精心设计的代码库易于理解、修改和扩展,从而能够灵活地适应不断变化的业务环境需求。

一致的代码设计对于团队的生产力和项目的长期可维护性至关重要。然而,实现这一点并非易事。它需要所有团队成员清晰的沟通、共同的理解和严谨的纪律。难点在于每个开发人员都有其独特的编码风格和解决问题的方法。随着时间的推移,如果没有齐心协力保持一致性,代码库可能会变成各种风格和模式的拼凑物,使其难以理解和维护。

我想分享一种基于 ArchUnit 的方法——为您的代码进行单元测试。

ArchUnit 是由 TNG 开发的一个功能强大的库,它将架构控制权直接引入到你的代码库中。该项目的核心思想是验证 Java 代码库中的架构规则,确保遵循你设定的设计原则和标准。

该库提供了一种领域特定语言 (DSL),允许您以清晰、简洁的方式表达架构规则。这使得开发人员更容易理解和执行这些规则,从而实现更一致、更易于维护的代码库。

@AnalyzeClasses(packages = "com.tngtech.archunit.example.layers")
public class MethodsTest {
    @ArchTest
    static ArchRule codeUnitsInDAOLayerShouldNotBeSecured =
            noCodeUnits()
                    .that().areDeclaredInClassesThat().resideInAPackage("..persistence..")
                    .should().beAnnotatedWith(Secured.class);
}

Enter fullscreen mode Exit fullscreen mode

使用 ArchUnit 的主要优势之一是它能够及早发现架构违规。ArchUnit 无需等待代码审查或架构审计,只需在代码编写完成后即可发现问题。这可以更快地获得反馈并减少技术负担。

此外,ArchUnit 灵活且可扩展,允许您根据项目的独特需求定义自定义规则。它与 JUnit 等流行的测试框架无缝集成,非常适合任何 Java 项目。

例如,当您更喜欢 AssertJ 库时,您可以禁用 JUnit 断言:

@Test
  void isTestClassesDontUseJunitAssertions() {
    ArchRuleDefinition.noClasses()
        .should()
        .dependOnClassesThat()
        .haveNameMatching("org.junit.jupiter.api.Assertions")
        .check(importedTestClasses);
  }
Enter fullscreen mode Exit fullscreen mode

或者对于 Spring,您可以添加对控制器名称的限制:

@Test
  void controllerNameRule() {
    classes()
        .that()
        .areAnnotatedWith(RestController.class)
        .should()
        .haveSimpleNameContaining("Controller")
        .check(importedClasses);
  }
Enter fullscreen mode Exit fullscreen mode

甚至可以检查 RequestBody 中的验证使用情况:

@Test
  void restControllerValidationRule() {
    classes()
        .that()
        .areAnnotatedWith(RestController.class)
        .should()
        .beAnnotatedWith(Validated.class)
        .check(importedClasses);
  }

@Test
  void restControllerValidationRequestBodyRule() {
    classes()
        .that()
        .areAnnotatedWith(RestController.class)
        .should(
            new ArchCondition<>("Any @RequestBody must be @Valid") {
              @Override
              public void check(JavaClass javaClass, ConditionEvents conditionEvents) {
                for (JavaMethod method : javaClass.getMethods()) {
                  if (method.isConstructor()) {
                    continue;
                  }

                  for (Parameter parameter : method.reflect().getParameters()) {
                    if (parameter.isAnnotationPresent(RequestBody.class)
                        && !parameter.isAnnotationPresent(Valid.class)) {
                      conditionEvents.add(
                          new SimpleConditionEvent(
                              javaClass,
                              false,
                              javaClass.getName()
                                  + " contains method "
                                  + method
                                  + " with @RequestBody and without Valid"));
                    }
                  }
                }
              }
            })
        .check(importedClasses);
  }
Enter fullscreen mode Exit fullscreen mode

当然,ArchUnit 的强大功能之一就是它的预定义规则。这些规则为在 Java 代码库中强制执行架构标准提供了坚实的基础。它们涵盖了各种常见的架构场景,让您可以更轻松地开始架构控制。

这些预定义规则可以按原样使用,也可以作为创建自定义规则的起点。这种灵活性使您可以根据项目的特定需求定制 ArchUnit,从而确保以对您的团队和代码库有意义的方式维护您的架构标准。

本质上,ArchUnit 的预定义规则是维护架构完整性、减少技术债务和提高代码整体质量的宝贵工具。它们证明了该库的强大功能和多功能性,使其成为任何认真对待架构的 Java 开发人员的必备工具。

您可以在 com.tngtech.archunit.library.GeneralCodingRules 中找到一般预定义规则,例如:

  • 任何类都不应访问标准流
  • 任何类都不应抛出通用异常
  • 任何类都不应该使用 JODATIME
  • 任何类都不应该使用 JAVA_UTIL_LOGGING
  • 任何类都不应使用字段注入

com.tngtech.archunit.library.DependencyRules 中提供了依赖规则:

  • 任何类都不应依赖于上层软件包

您可以在官方用户指南https://www.archunit.org/userguide/html/000_Index.html或 github 存储库https://github.com/TNG/ArchUnit中找到更多示例

总而言之,ArchUnit 是一款非常有价值的工具,可以维护代码库架构的完整性、提高一致性、减少技术债务并提升整体代码质量。对于任何认真对待架构的团队来说,它都是必备工具。

作者是 Mark Andreev,SWE@Conundrum.ai

鏂囩珷鏉ユ簮锛�https://dev.to/mrkandreev/how-to-create-unit-tests-for-code-design-5g9i
PREV
AdminUI 上下文解决方案替代方案的 Vaadin Flow
NEXT
JavaScript 中的机器学习基础知识