[英]sbt doesn't correctly deal with resources in multi-module projects when running integration tests. Why?
I have the following configuration on an sbt project: 我在sbt项目上具有以下配置:
moduleA
Contains a bunch of integration tests. moduleA
包含许多集成测试。 moduleB
(depends on moduleA
). moduleB
(取决于moduleA
)。 Contains a reference.conf
file; reference.conf
文件; moduleC
(aggregates moduleA
and moduleB
-- this is the root). moduleC
(聚合moduleA
和moduleB
这是根)。 When I try to run it:test
I get errors, as the tests cannot find the values available on reference.conf
. 当我尝试运行
it:test
我得到了错误,因为测试找不到在reference.conf
可用的值。 Manually copying the reference.conf
to moduleA
makes it work. 手动将
reference.conf
复制到moduleA
使其起作用。
The issue seems clearly to be that by some reason when running the it:tests
(at the root), sbt is not smart enough to add the reference.conf
to the classpath. 问题似乎很明显是由于某种原因(在根目录下)运行
it:tests
时,sbt不够聪明,无法将reference.conf
添加到类路径中。
Can anyone theorize why is that the case? 谁能推理出为什么会这样? How does sbt work with classpaths and classloaders?
sbt如何与类路径和类加载器一起工作? Will it just dump everything in a single classloader?
它将仅将所有内容转储到单个类加载器中吗? It certainly doesn't seem to be the case.
似乎并非如此。
Thanks 谢谢
In order to address your question and comment, let me break down what SBT is doing with your project. 为了解决您的问题和评论,让我分解一下SBT对您的项目所做的事情。
ModuleC
is the root project, and it aggregates ModuleA
and ModuleB
. ModuleC
是根项目,它聚合 ModuleA
和ModuleB
。 In the context of SBT , aggregation means that any command that is run on the root project is also run on the aggregated sub-projects. 在SBT的上下文中, 聚合意味着在根项目上运行的任何命令也将在聚合的子项目上运行。 So, for example, if you run integration tests on the root module, then you will also run the integration tests for its aggregated modules.
因此,例如,如果您在根模块上运行集成测试,那么您还将为其聚合模块运行集成测试。 However, it's important to understand that this is not done all-at-once : the command is run on each sub-project individually.
但是,重要的是要了解这并非一次完成 :该命令在每个子项目上单独运行。
The next question that SBT has to address is the order in which the sub-projects should be processed. SBT必须解决的下一个问题是子项目的处理顺序。 In this case, since
ModuleB
depends on ModuleA
, it has to process ModuleA
before processing ModuleB
. 在这种情况下,由于
ModuleB
依赖 ModuleA
,因此它必须在处理ModuleA
之前先处理ModuleB
。 Otherwise, if there was no dependency between them, then the order wouldn't matter, and SBT would most likely stick with the order that they were specified in ModuleC
's aggregation list. 否则,如果它们之间没有依赖关系,则顺序将无关紧要, SBT很有可能会
ModuleC
在ModuleC
的聚合列表中指定的顺序。
But what does it mean for one sub-project to depend upon another? 但是,一个子项目依赖另一个项目意味着什么? It's akin to the relationship between an SBT project and one of its
libraryDependencies
: the dependent library must be available to the sub-project, and its resources and classes are made available on the classpath during the indicated phases (compile, test, run, etc.). 这是类似于一个SBT项目和它的一个关系
libraryDependencies
:因库必须提供给子项目,它的资源和类中指定的阶段(编译,测试,运行等提供的类路径)。
So, when integration tests are run on ModuleC
, SBT will first run ModuleA
's integration tests. 因此,当在
ModuleC
上运行集成测试时, SBT将首先运行ModuleA
的集成测试。 Since ModuleA
has no other dependencies within the project, it will be processed without any of the other sub-projects available on its classpath . 由于
ModuleA
在项目中没有其他依赖项,因此将对其进行处理, 而其classpath上没有任何其他子项目 。 (This is why it cannot access the reference.conf
file that is part of ModuleB
.) This makes sense, if you think about it, because otherwise—if ModuleA
and ModuleB
are dependent upon each other—you would have an unresolvable chicken-and-egg situation, in which neither project could be built. (这就是为什么它不能访问
ModuleB
一部分的reference.conf
文件的原因。)如果考虑一下,这是有道理的,因为否则,如果ModuleA
和ModuleB
相互依赖,那么您将无法解决- -egg情况,无法建立任何项目。
(BTW, if ModuleA
has sources that have not yet been compiled, then they will be compiled, on a separate compile pass, before running the integration tests.) (顺便说一句,如果
ModuleA
源代码尚未编译,则将在运行集成测试之前通过单独的编译过程对其进行编译。)
Next it will try to process ModuleB
, adding ModuleA
's resources and classes to its classpath, since it is dependent upon them. 接下来,它将尝试处理
ModuleB
,将ModuleA
的资源和类添加到其类路径中,因为它依赖于它们。
From your description, it seems that at least some of the configuration settings in ModuleB
's reference.conf
file should belong to ModuleA
, since it needs access to them during its integration tests. 从您的描述看来,
ModuleB
的reference.conf
文件中的至少某些配置设置应该属于ModuleA
,因为它需要在集成测试期间访问它们。 Whether this means that the whole of the file should belong to ModuleA
is up to you. 这是否意味着整个文件应属于
ModuleA
取决于您。 However, it's possible for each sub-project to have its own reference.conf
file resource (that's a design feature of the Typesafe Config library that I'm assuming you're using). 但是,每个子项目都有可能拥有自己的
reference.conf
文件资源(这是我假设您正在使用的Typesafe Config库的设计功能)。 Any configuration settings that belong to ModuleA
's reference.conf
file will also be available to ModuleB
, since it is dependent upon ModuleA
. 属于
ModuleA
的reference.conf
文件的任何配置设置也将可供ModuleB
,因为它取决于ModuleA
。 (If you have multiple reference.conf
files, the only issue you have will depend upon how you package and release ModuleC
. If you package everything in all of your sub-projects into a single JAR file, then you would need to merge the various reference.conf
files together, for example.) (如果您有多个
reference.conf
文件,则唯一的问题取决于打包和释放ModuleC
。如果将所有子项目中的所有内容打包到一个JAR文件中,则需要合并各种例如,将reference.conf
文件放在一起。)
Another possibility is that some or all of the integration tests should actually belong to ModuleC
rather than either ModuleA
or ModuleB
. 另一种可能性是,某些或所有集成测试实际上应该属于
ModuleC
而不是ModuleA
或ModuleB
。 Again, making this determination will depend upon your requirements. 同样,做出此决定将取决于您的要求。 If it makes sense for each sub-project to perform integration tests in all cases, then place them in the sub-projects.
如果每个子项目在所有情况下都执行集成测试是有意义的,则将它们放在子项目中。 If they only make sense for the completed project as a whole, then put them in
ModuleC
. 如果它们仅对整个已完成的项目有意义,则将它们放在
ModuleC
。
You might want to read the documentation for SBT multi-project builds for further details. 您可能需要阅读SBT多项目构建的文档,以获取更多详细信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.