>我在 sbt 项目上有以下配置:
moduleA
包含一堆集成测试。moduleB
(取决于moduleA
(。包含一个reference.conf
文件;moduleC
(聚合moduleA
和moduleB
- 这是根(。
当我尝试运行it:test
时出现错误,因为测试找不到reference.conf
上可用的值。手动将reference.conf
复制到moduleA
即可使其正常工作。
问题似乎很明显,由于某种原因,在运行it:tests
(在根目录(时,sbt 不够聪明,无法将reference.conf
添加到类路径中。
谁能从理论上讲为什么会这样?sbt 如何与类路径和类装入器配合使用?它会将所有内容转储到单个类加载器中吗?情况似乎并非如此。
谢谢
为了解决您的问题和评论,让我分解一下SBT对您的项目所做的工作。
ModuleC
是根项目,它聚合ModuleA
和ModuleB
。在SBT上下文中,聚合意味着在根项目上运行的任何命令也在聚合的子项目上运行。因此,例如,如果在根模块上运行集成测试,则还将对其聚合模块运行集成测试。但是,重要的是要了解这不是一次性完成的:该命令在每个子项目上单独运行。
SBT必须解决的下一个问题是处理子项目的顺序。在这种情况下,由于ModuleB
取决于ModuleA
,因此它必须在处理ModuleB
之前处理ModuleA
。否则,如果它们之间没有依赖关系,那么顺序就无关紧要了,SBT很可能会坚持它们在ModuleC
聚合列表中指定的顺序。
但是,一个子项目依赖于另一个子项目意味着什么?这类似于SBT项目与其libraryDependencies
之一之间的关系:依赖库必须可供子项目使用,并且其资源和类在指定的阶段(编译、测试、运行等(在类路径上可用。
所以,当集成测试在ModuleC
上运行时,SBT将首先运行ModuleA
的集成测试。由于ModuleA
在项目中没有其他依赖项,因此将在其类路径上没有任何其他子项目的情况下对其进行处理。(这就是为什么它无法访问作为ModuleB
一部分的reference.conf
文件的原因。如果你考虑一下,这是有道理的,因为否则——如果ModuleA
和ModuleB
相互依赖——你将面临一个无法解决的先有鸡还是先有蛋的情况,在这种局面下,两个项目都无法构建。
(顺便说一句,如果ModuleA
有尚未编译的源代码,那么在运行集成测试之前,它们将在单独的编译过程中进行编译。
接下来它将尝试处理ModuleB
,将ModuleA
的资源和类添加到它的类路径中,因为它依赖于它们。
从您的描述来看,似乎至少有一些ModuleB
reference.conf
文件中的配置设置应该属于ModuleA
,因为它在集成测试期间需要访问它们。这是否意味着整个文件应该属于ModuleA
取决于您。但是,每个子项目都可以有自己的reference.conf
文件资源(这是我假设您正在使用的Typesafe Config库的设计功能(。任何属于ModuleA
的reference.conf
文件的配置设置也可供ModuleB
使用,因为它依赖于ModuleA
。(如果您有多个reference.conf
文件,您遇到的唯一问题将取决于您如何打包和发布ModuleC
。例如,如果将所有子项目中的所有内容打包到单个JAR文件中,则需要将各种reference.conf
文件合并在一起。
另一种可能性是,部分或全部集成测试实际上应该属于ModuleC
,而不是ModuleA
或ModuleB
。同样,做出此决定将取决于您的要求。如果每个子项目在所有情况下都执行集成测试是有意义的,则将它们放在子项目中。如果它们只对整个已完成的项目有意义,那么将它们放在ModuleC
.
有关更多详细信息,您可能需要阅读SBT 多项目构建的文档。