Java 检索路径以处理测试期间出现问题的文件
我正在为我的程序开发Ant builder,特别是处理文件路径 我找到了一个非常简单的解决方案,只需在常量界面中添加两个字段:Java 检索路径以处理测试期间出现问题的文件,java,eclipse,testing,ant,powermock,Java,Eclipse,Testing,Ant,Powermock,我正在为我的程序开发Ant builder,特别是处理文件路径 我找到了一个非常简单的解决方案,只需在常量界面中添加两个字段: /** The actual jar file where the class is run */ public static final File JAR_FILE = new File(MagicHogwarts.class.getProtectionDomain().getCodeSource().getLocation().getPath()); /** Th
/** The actual jar file where the class is run */
public static final File JAR_FILE = new File(MagicHogwarts.class.getProtectionDomain().getCodeSource().getLocation().getPath());
/** The path to the main folder where the file .jar is run */
public static final String BASE_DIRECTORY = JAR_FILE.getAbsolutePath().replace(JAR_FILE.getName(), "");
在处理文件的每个方法中,我只需询问jar所在主文件夹的相对路径,然后首先添加BASE_目录,至少在运行jar的eclipse中的macOSX中都可以正常工作
很高兴有了这个快速解决方案,我运行了我的测试。那失败了。
问题似乎在Constants接口中,无法创建JAR\u文件
,因为getLocation
返回null,然后getPath
失败
但我不明白为什么
因此,我尝试模拟接口,由于var声明为static final,因此存在明显的问题,因此我尝试使用PowerMock:
@RunWith(PowerMockRunner.class)
@PrepareForTest({GameWindow.class,Constants.class})
public class MapReaderTest {
@Test
public void testReadingExampleMap() throws Exception {
mockStatic(GameWindow.class);
mockStatic(Constants.class);
TextureLoader tl = createMock(TextureLoader.class);
Texture tx = createMock(Texture.class);
expect(GameWindow.getTextureLoader()).andReturn(tl);
expect(Constants.BASE_DIRECTORY).andReturn("/Users/Gianmarco/Documents/java/MagicHogwarts/").anyTimes();
expect(tl.getTexture("/Users/Gianmarco/Documents/java/MagicHogwarts/bin/mh/test/sewer_tileset.png")).andReturn(tx);
expect(tx.getImageHeight()).andReturn(32).anyTimes();
expect(tx.getImageWidth()).andReturn(32).anyTimes();
replay(GameWindow.class);
replay(Constants.class);
replay(tl);
replay(tx);
// Act
Map map = new TMXMapReader().readMap("/bin/mh/test/sewers.tmx");//mapFile.getAbsolutePath());
// Assert
assertEquals(Map.ORIENTATION_ORTHOGONAL, map.getOrientation());
assertEquals(50, map.getHeight());
assertEquals(50, map.getHeight());
assertEquals(24, map.getTileWidth());
assertEquals(24, map.getTileHeight());
assertEquals(2, map.getLayerCount());
}
}
但我得到了一个ExceptionInInitializerError,常量的第60行,即声明JAR_文件的那一行,该错误是由NullPointerException引起的
我认为下一步是将接口转换为类,也许powermock无法以这种方式处理接口
运行,并得到一个NoClassDefFoundError。
仍然没有结果,我不知道该怎么办。所以我试着反思
我使用了这种静态方法:
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
// remove final modifier from field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
称之为:
setFinalStatic(Constants.class.getField("JAR_FILE"), null);
setFinalStatic(Constants.class.getField("BASE_DIRECTORY"), "my/path/hardcoded");
但这两种方法都不起作用,我得到了一个ExceptionInInitializerRor,其堆栈包含sun.mic.Unsafe.EnsureClassified(本机方法)
、sun.reflect和其他内容
我花了几个小时研究这个问题,得出的结论是JAR_文件和用于初始化它的方法有问题,因为即使从常量中删除final
修饰符,我也无法更改调用constants.JAR_FILE=null
我解决问题的方法是:
/** The actual jar file where the class is run */
public static final File JAR_FILE = (MagicHogwarts.class.getProtectionDomain().getCodeSource().getLocation() == null ? null : new File(MagicHogwarts.class.getProtectionDomain().getCodeSource().getLocation().getPath()));
/** The path to the main folder where the file .jar is run */
public static final String BASE_DIRECTORY = (JAR_FILE != null ? JAR_FILE.getAbsolutePath().replace(JAR_FILE.getName(), "") : "/Users/Gianmarco/Documents/java/MagicHogwarts/");
这是使用if语句的一种粗鲁、非常不愉快和可怕的方式
我的问题是,是否有任何不同的方法可以从终端行获取jar的base dir和/或用#javamyclass
调用的文件,这些方法既可以用于正常处理(也可以是jar),也可以用于测试
我找到的解决方案是可行的,但我不认为将一些测试代码硬编码到类中是一件好事,事实上使用if就像告诉Constants类“如果我正在测试,给我这个模拟字符串,否则给我真正的路径”。如果在正常的程序行为中没有用处,我希望将测试代码与类分开(应该如此)。测试时不应该依赖绝对路径,因为它会使测试变得脆弱和不可移植 我们应该寻找资源,而不是绝对路径。最好使用Class.getResource或Class.getResourceAsStream进行读取
对于前者,您可以检索URL。如果有必要,可以使用url.toExternalForm将其转换回绝对路径,但一旦您拥有了所需的资源,就应该足够了 您可以通过各种方法获取JAR文件的位置,您已经尝试了一些。这听起来像是在运行测试时,您是针对原始
.class
文件运行的,并且没有JAR文件。寻找一种方法来利用Class.getResource()
或Class.getResourceAsStream()
并在测试类路径上显示所需内容,而不是在磁盘上查找文件。另外,请记住,静态常量字符串是内联的,用于可能发生更改的对象是危险的。