ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ktlint CLI 测试夹具机制:`.test` 扩展名约定与自举 lint 隔离策略

ktlint CLI 测试夹具机制:`.test` 扩展名约定与自举 lint 隔离策略 开发工具代码质量Lint格式化【免费下载链接】ktlintAn anti-bikeshedding Kotlin linter with built-in formatter项目地址https://gitcode.com/gh_mirrors/kt/ktlint点击查看免费下载导读本文围绕 ktlint 仓库中 ktlint-cli/src/test/resources/cli/readme.md 所定义的测试资源组织约定展开为什么 CLI 测试目录下的大部分 Kotlin 文件都故意携带 lint 违规、为什么这些文件必须以.test作为扩展名结尾、以及no-code-style-error/Main.kt为何是唯一的例外。读完本文你将理解 ktlint 如何在不污染自身代码库的前提下为命令行工具构造真实可复现的 lint 输入并能把这套带违规源码夹具 扩展名隔离的方法复用到你自己的测试项目中。一、问题背景CLI 测试需要故意写坏的源码ktlint 的 CLIktlint-cli 模块负责把源码文件喂给规则引擎并输出 lint 报告。要测试这类功能最直接的做法是准备一些必然产生违规的 Kotlin 源码作为输入再断言 CLI 的输出、退出码与格式化结果。但这里存在一个自举dogfooding矛盾ktlint 项目自身也在用 ktlint 做静态检查。如果测试夹具里的坏代码使用了正常的.kt扩展名那么当开发者在仓库根目录运行ktlint检查项目自身时这些故意制造的违规文件也会被扫描到导致项目 lint 一直红。cli/readme.md正是对这一矛盾的直接回答原文明确指出Most of the kotlin files in this directory contain lint violations which are required for testing. Files that do contain lint errors have extension.test. This additional extension prevents that the file is being picked up by ktlint when running it on the project itself. Fixing the lint violations in those files results in failing tests in the next test run.即该目录下大多数 Kotlin 文件故意包含测试所需的 lint 违规凡是带违规的文件都以.test结尾这个额外扩展名确保项目自检时不会扫描到它们而任何人若好心修掉这些文件里的违规下一次测试运行就会失败。二、核心约定解读.test扩展名如何实现双重隔离2.1 对项目自检的隔离默认模式只匹配.kt/.ktsktlint 在不指定任何 glob 时会启用一套默认文件模式。该模式定义在 FileUtils.ktprivate val DEFAULT_KOTLIN_FILE_EXTENSIONS setOf(kt, kts) internal val DEFAULT_PATTERNS DEFAULT_KOTLIN_FILE_EXTENSIONS.map { **/*.$it }默认 glob 是**/*.kt与**/*.kts。因此Foo.kt.test、Main.kt.test这类文件不会被默认模式命中从而在项目自检中被自动跳过需要被测试拾取的文件则保持正常扩展名见下文no-code-style-error/Main.kt。也就是说.test是附加在.kt/.kts之后的尾部扩展名它既让夹具文件在语义上仍是Kotlin 源码又使其对默认 glob 完全不可见。2.2 对测试的完整性保障夹具不可被修好readme.md还强调了一个反向约束Fixing the lint violations in those files results in failing tests in the next test run修复这些文件中的违规会导致下一次测试失败。这是把测试夹具从一次性样例升级为活体断言每个带.test的文件其违规内容本身就是测试预期的一部分测试断言assertErrorExitCode()并匹配具体的错误消息如Needless blank line(s)、First line in a method block should not be empty一旦有人修改夹具、消除违规对应断言立刻落空测试随即失败。这样即使未来重构也不会有人在不经意间顺手修掉测试输入保证了回归测试的长期稳定性。2.3 唯一的例外no-code-style-error/Main.ktreadme.md特别声明了一个例外File no-code-style-error/Main.kt does not contain a lint violation and its file name does not end with .test as the files needs to be picked up by a test which tests the default kotlin extension.该文件位于 no-code-style-error/Main.kt内容是完全合规的fun main() { println(Hello world!) }它既没有违规、也没有.test后缀因为它的使命就是验证默认扩展名拾取机制当测试不传任何 glob 时ktlint 应当通过默认模式**/*.kt找到并扫描这个文件。这一点由 SimpleCLITest.kt 中的用例直接印证对no-code-style-error测试项目运行不带任何模式参数的 ktlint断言输出包含Enable default patterns与1 file(s) scanned / 0 error(s)因为该文件无违规最终退出码为 0。这个用例同时验证了两件事默认模式确实生效且无违规输入应当干净地通过 lint。三、测试运行器夹具如何被消费仅仅摆放夹具文件还不够测试还需要在隔离环境中真实地执行 ktlint CLI。这由 CommandLineTestRunner.kt 完成其机制与cli/资源目录紧密配合复制夹具到临时目录prepareTestProject(testProjectName)将src/test/resources/cli/projectName整个目录递归复制到 JUnit 的TempDir中确保每次测试都从干净的基线状态出发源目录中Main.kt.test的原始内容不会被--format破坏。独立进程执行通过ProcessBuilder启动一个全新的 shellWindows 上为cmd.exe /C其余平台为/bin/sh -c调用打包好的 ktlint CLI jar并传入测试参数例如--log-leveltrace与断言所需的 glob。捕获输出与退出码测试进程结束时打印Exit ktlint with exit code: n调试行运行器从标准输出末行解析出退出码随后交给ExecutionResultassertNormalExitCode()/assertErrorExitCode()/assertErrorOutputIsEmpty()完成断言。格式化结果对比assertSourceFileWasFormatted(filePathInProject)将临时目录中被--format改写过的文件与src/test/resources中的原始文件对比验证格式化确实修改了内容。简言之cli/目录是测试数据的种子临时目录是每次测试的沙箱二者结合让每个 CLI 用例都具备真实进程、真实文件系统与可重复的结果。四、各测试资源子目录与对应用例cli/目录按测试主题组织了多个子项目每个子项目就是一套迷你坏代码仓库测试资源目录夹具内容验证的 CLI 行为对应测试no-code-style-error唯一无违规的Main.kt无.test默认模式**/*.kt拾取、无错误退出SimpleCLITesttoo-many-empty-linesMain.kt.test含多余空行错误退出码、Needless blank line(s)报告、--format自动修复、reporter 输出SimpleCLITestbaseline同名.kt.test文件 基线 XML--baseline忽略已登记违规、保留未登记违规BaselineCLITestcustom-ruleset规则集 jar 文件-R加载外部规则集、无效 jar 报错、已废弃RuleSetProviderV3警告RuleSetsLoaderCLITesteditorconfig-path带.editorconfig的嵌套项目--editorconfig指定配置路径EditorConfigDefaultsLoaderCLITestnested-editorconfig含子目录.editorconfig覆盖--stdin --stdin-path合并根目录与子目录配置SimpleCLITestIssue 3296ignore-autocorrect-failuresFoo.kt文件名违规--format下无法自动修复的违规默认报错、--ignore-autocorrect-failures时忽略SimpleCLITest其中ignore-autocorrect-failures的用例值得注意它运行--format时standard:filename这类无法自动修复的违规默认仍会导致错误退出码并标注(cannot be auto-corrected)只有显式加上--ignore-autocorrect-failures后退出码才恢复为 0。这体现了.test夹具之外个别场景如Foo.kt也可以借助--format的不可修复语义来构造预期。五、基线baseline夹具的刻意设计baseline/readme.md 对基线夹具列出了四点刻意配置每一点都对应一类边界行为test-baseline.xml与config/test-baseline.xml内容完全一致用于验证--baseline既支持工作目录根部的相对路径也支持子目录路径config/test-baseline.xml甚至支持绝对路径BaselineCLITest用$tempDir/baseline/config/test-baseline.xml验证。基线中的规则引用不带规则集 idstandard:验证基线匹配机制对规则id:规则名前缀的处理即基线文件里不写standard:...前缀也能正确忽略对应违规。所有测试文件都含一个已登记到基线的空函数体违规保证在给定基线时这两处违规必须被静默忽略退出码 0从而证明基线确实生效。TestBaselineExtraErrorFile额外包含一条未登记的错误单行块注释该额外违规不在基线中因此 lint 时必须被原样报告退出码非 0证明基线只豁免已登记项、不搞一刀切。配套断言位于 BaselineCLITest.kt忽略基线时两处Unnecessary block都要报错应用基线后同样文件不再报错而对TestBaselineExtraErrorFile.kt.test基线挡不住那条Replace the block comment with an EOL comment。这套设计让基线豁免与未登记错误仍上报两个方向都有了明确用例。六、把该模式迁移到你的项目cli/readme.md定义的约定完全可以脱离 ktlint 项目单独复用为含违规的测试源码统一加后缀如.kt.test/.kts.test并让项目自身的 lint 命令CI、pre-commit hook只使用默认模式或显式 glob从而自动排除这些夹具夹具内容即测试预期每条违规都要有对应断言任何修正都会使测试失败从机制上防止夹具退化必要时保留一个纯净样板如同no-code-style-error/Main.kt用无违规且无后缀的文件专门验证默认扫描入口与干净通过的路径在隔离沙箱中运行将夹具目录复制到临时目录后再执行真实 CLI 进程避免格式化用例--format原地改写测试资源、造成测试间相互污染为边界场景准备刻意差异像baseline/那样让两个基线文件内容相同但路径不同、让某个文件比基线多一条违规从而一次性覆盖豁免与上报两个方向。七、小结cli/readme.md虽然只有寥寥数行却定义了 ktlint CLI 测试体系的基石约定用.test后缀隔离故意违规的夹具用唯一干净的Main.kt验证默认扩展名拾取再用修好即测试失败的机制守护夹具完整性。结合 FileUtils.kt 中的默认模式实现、CommandLineTestRunner.kt 的沙箱运行机制以及 SimpleCLITest.kt、BaselineCLITest.kt、RuleSetsLoaderCLITest.kt 等用例这套坏代码即资产的测试夹具设计是理解 ktlint CLI 行为与构建高质量 linter 测试的绝佳范本。赞分享开发工具代码质量Lint格式化【免费下载链接】ktlintAn anti-bikeshedding Kotlin linter with built-in formatter项目地址https://gitcode.com/gh_mirrors/kt/ktlint点击查看免费下载相关推荐Media Downloader扩展沙箱机制安全隔离与资源限制策略Media Downloader扩展沙箱机制安全隔离与资源限制策略 在当今数字内容爆炸的时代媒体下载工具已成为许多用户不可或缺的帮手。然而随着网络威胁日益桌面应用音视频Laravel-Permission测试策略与自定义扩展Laravel Permission测试策略与自定义扩展 本文详细探讨了Laravel Permission包的全面测试策略和自定义扩展方法。文章首先深入分析了后端认证鉴权Zulip 自动化测试体系完全指南从 test-all 到单测隔离策略Zulip 自动化测试体系完全指南从 test all 到单测隔离策略 Zulip 是少数把测试套件当作第一等基础设施来建设的开源项目它的后端测试套件 te即时通讯后端前端WebSocket上一篇阴阳师自动化脚本3分钟快速上手指南与完整配置教程下一篇Krita AI Diffusion零基础快速掌握AI绘画的终极完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表