在我以前的articles中,我已经谈论过有时我们甚至没有注意到我们周围的算法。当使用工具或库时,我们将其作为给定食用,甚至不理解幕后的工作方式。今天,我将逆向工程算法开玩笑来查找相关测试时,我们运行jest --findRelatedTests
。
什么是玩笑,我如何使用它?
Jest是当今几乎每个项目中使用的流行JavaScript测试框架。您可以简单地通过使用test.js
扩展名创建任何测试文件并在您的终端中运行嘲笑命令开始。 JEST还提供了广泛的配置选项开发人员可以用来定义要包括/排除的测试,要生成的覆盖范围输出,以哪种格式,如何移动源文件等。-您可以在official docs中找到所有这些。最令人兴奋的选项是用--findRelatedTests
和要测试的文件的传递列表来运行开玩笑:
jest --findRelatedTests /path/to/file1, /path/to/file2
这种方式开玩笑将不仅运行与这些文件关联的直接测试,还将运行对传递依赖性的测试。优化GIT预命令命令执行时,它变得非常方便。开玩笑只会运行一组测试,而不是每当您要进行新的更改时,就不会运行一组测试,而是要运行一组测试,这些测试实际上会受到相应的更改节省开发人员的影响,同时准确地与结果进行准确。
有一个文件系统
玩笑使用自定义的haste module system以优化的方式构建有关文件和依赖关系的元数据。这个组成部分绝对值得在《胡德》文章下得到自己的。就目前而言,让我们简化它提供了API,以以下形式获取项目中的所有文件及其依赖项的集合:
Array<{
// absolute file path
file: string;
// list of depedencies (modules imported in current file)
dependencies: Array<string>;
}>
看着引擎盖
我们知道什么:
- 已在git 中添加/修改/删除并上演的一组文件
- 和整个文件系统元数据
现在,我们需要找到一种算法来检测并运行仅受此更改影响的测试文件。
和Jest提供resolveInverse API来解决此问题:
resolveInverse(
paths: Set<string>,
filter: (file: string) => boolean,
options?: ResolveModuleConfig, ): Array<string> {
return this.resolveInverseModuleMap(paths, filter, options)
.map( module => module.file, );
}
其中:
-
paths
是一组已更改的文件路径 -
filter
是一个谓词function,用于检测当前文件是否是测试文件 -
options
对象(与算法无关,暂时忽略它)
resolveInverseModuleMap
使用一种非常简单的方法来解决基于Breadth First Search(BFS)的问题。首先,它初始化以下集:
-
changed
-受影响的一组文件。基本上,这是一个临时集,在每次BFS的每次迭代后都会突变,并用作终止指示器 - 算法在空为空时会停止。在第一次迭代中,该集合由提供的paths
填充。 -
relatedPaths
- test 文件的集合。默认情况下,该集合是从paths
输入中填充的,但条件是该文件实际上是一个测试文件。在BFS的每次迭代中,每个匹配的测试文件都从此文件中删除。在算法的末尾,该集合中的剩余文件路径与BFS执行的结果相连。这是在测试文件中而不是在源中进行更改时处理简单的用例。 -
visitedModules
-已经被遍历并可以从进一步处理中跳过的文件。
所以让我们可视化我们的算法。首先,让我们定义我们的示例文件系统:
红色表示的块表示更改的模块(矩形是测试文件,而圆圈是源文件)。箭头从父到子开始(这意味着a
模块由a.test
和a1
导入)。最初,我们的数据结构看起来像这样:
我们的changed
套件不是空的。这意味着我们需要遍历文件系统中的所有文件,以获取changed
集中每个模块的依赖项列表。在第一次迭代之后,我们已经发现至少b.test
和a1.test
需要分别作为a.test
和a1
的依赖项运行:
做另一个遍历。现在,我们看到b2
已导入a.test
和b2.test
,但是我们在最初更改的文件中已经有a.test
。在这种情况下,我们需要将其从relatedPaths
集中删除,并将其添加到结果中。如果a.test
没有任何依赖性,JEST将其返回到上游呼叫者时简单地将结果合并为结果。
最后,我们在changed
集中只有2个测试模块,并且已经看到a.test
在我们访问的集合中,而b2.test
没有任何依赖人。基本上,这里的no -op-此迭代后,更改集将变为空,我们将脱离BFS循环。
结果,我们可以将测试范围从5个测试文件缩小到4。这并不令人印象深刻,但请记住,我为简单起见选择了一个很小的数据集,在现实世界项目中,将会有数千个文件,并且改进确实可以很大。
您可以找到原始实现[此处] (https://github.com/facebook/jest/blob/e865fbd66e3dc4adf9d35a35ce91de1bee48bc93/packages/jest-resolve-dependencies/src/index.ts#L99)_._
最后的想法
您认为该算法可以改善吗?如果我们可以作为文件元数据的一部分(类似于对父母的引用的DOM元素)具有与因模块的逆链接,该怎么办?在这种情况下,我们不必遍历整个文件系统,而只专注于一个子集。
最初于2022年12月22日在 https://thesametech.com 发表。
您也可以 follow me on Twitter , subscribe to my Telegram channel,和和 connect on LinkedIn 以获取有关新帖子的通知!