我有一堆包含如下代码的单元测试:
File file = new File("src/main/java/com/pany/Foo.java");
assertTrue("Missing file: " + file.getAbsolutePath(), file.exists());
使用Maven Surefire和-DforkCount=0
运行该测试时,该测试突然失败。使用-DforkCount=1
,它可以工作。
到目前为止我尝试过的事情:
更多详细信息:
forkCount=0
的原因,在这种情况下,该方法通常可以帮助您了解为什么分叉的VM崩溃了。 ulimit
(来自Cygwin)说:
$ ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
open files (-n) 256
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 2032
cpu time (seconds, -t) unlimited
max user processes (-u) 256
virtual memory (kbytes, -v) unlimited
我想知道256个“打开文件”限制是否仅适用于Cygwin进程,还是Cygwin从Windows读取的内容?
让我知道您是否还有其他需要。我没有办法尝试的想法。
Bernhard要求我打印绝对名称。我的回答是我已经在使用绝对名称,但是我错了。实际的代码是:
File file = new File("src/main/java/com/pany/Foo.java");
if (!file.exists()) {
log.debug("Missing file {}", file.getAbsolutePath());
... fail ...
}
... do something with file...
我现在将其更改为:
File file = new File("src/main/java/com/pany/Foo.java").getAbsoluteFile();
if (!file.exists()) {
log.debug("Missing file {}", file);
}
并解决了该问题。我只是不明白为什么。
当Maven创建一个分叉的VM以使用Surefire运行测试时,它可以更改当前目录。因此,在这种情况下,有意义的是,测试在分支时可以工作,但在同一VM中运行时将失败(因为VM是在多模块构建的根文件夹中创建的)。但是,为什么在调用exists()
之前将路径设为绝对路径才能解决此问题?
答案 0 :(得分:8)
一些背景。每个进程都有“当前目录”的概念。从命令行启动时,它就是执行命令的目录。从UI启动时,通常是程序(.exe文件)所在的文件夹。
在命令提示符或BASH中,您可以使用cd
更改此文件夹,以运行命令提示符。
Maven构建多模块项目时,必须为每个模块更改此设置(以便相对路径src/main/java/
始终指向正确的位置)。不幸的是,Java在任何地方都没有“设置当前目录”方法。创建新流程时只能指定一个,并且可以修改系统属性user.dir
。
这就是new File("a").exists()
和new File("a").getAbsoluteFile().exists()
工作不同的原因。
后者将使用new File(System.getProperty("user.dir"), "a")
确定路径,而前者将使用Windows API函数_wgetdcwd
(docs),该函数依次使用Windows进程的字段来获取路径。当前目录-在我们的例子中,始终是Maven最初所在的文件夹,因为当有人更改user.dir
时Java不会更新进程中的字段,并且Maven只能将此属性更改为“模拟”更改的文件夹。
WinNTFileSystem_md.c
呼叫fileToNTPath()
。这是在io_util_md.c
中定义的,并调用pathToNTPath()
。对于相对路径,它将调用currentDirLength()
,后者调用currentDir()
,后者_wgetdcwd()
。
另请参阅:
这是Surefire插件修改属性user.dir
的地方:https://github.com/apache/maven-surefire/blob/56d41b4c903b6c134c5e1a2891f9f08be7e5039f/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java#L1060
不进行分叉时,会将其复制到当前VM的系统属性中:https://github.com/apache/maven-surefire/blob/56d41b4c903b6c134c5e1a2891f9f08be7e5039f/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java#L1133
答案 1 :(得分:1)
所以我have checked via printing out the system properties with some simple tests。
在通过maven-surefire-plugin测试期间,user.dir
将更改为多模块构建中相应模块的根。
但是正如我已经提到的,有一个可用的系统属性basedir
可用于正确处理需要通过File
访问它们的测试的位置... basedir
指向相应模块的pom.xml
的位置。
但是很遗憾,IDEA IntelliJ在测试运行期间未设置basedir
属性。
但这可以通过以下设置解决:
private String basedir;
@Before
public void before() {
this.basedir = System.getProperty("basedir", System.getProperty("user.dir", "Need to think about the default value"));
}
@Test
public void testX() {
File file = new File(this.basedir, "src/main/java/com/pany/Foo.java");
assertTrue("Missing file: " + file.getAbsolutePath(), file.exists());
}
这将在-DforkCount=0
和-DforkCount=1
的Maven Surefire中以及在IDE(仅选中IDEA IntelliJ)中使用。
是的,这是Maven Surefire插件中更改user.dir
的问题。
我们可以说服IDE也支持basedir
属性吗?
答案 2 :(得分:0)
亚伦,我们研发了Surefire。如果您提供以下方法,我们可以为您提供帮助:
assertTrue("Missing file: " + file.getAbsolutePath(), file.exists());
请发布您的POM所在的实际路径,预期路径和 basedir 。 该理论在这里无济于事。我们正在测试JDK 7-12的所有范围,但没有必须考虑的Cygwin + Windows组合。 您提到的Surefire中的代码设置 user.dir 存在了十年。