我有我的类
public class MappingLoader
{
private static final String filepath = "/tmp/mapping.properties" // unix path of production system
private static Map<String,String> mapping = new HashMap<String,String>()
static
{
loadMappingFile()
}
@VisibleForTesting
static void loadMappingFile()
{
//reading properties files here
final Properties prop = new Properties();
try (final InputStream input = Files.newInputStream(Paths.get(filepath)))
{
prop.load(input);
}
catch (final Exception e)
{
...
...
throw new RuntimeException(e);
}
//now load "mapping" from properties file
....
....
}
}
为了测试,我需要改变字符串变量"filepath"的值,以便它应该采用开发系统路径(例如c:projecttargetmapping.properties)
我在junits中尝试过powermock,但是它总是抛出异常并终止。
类级别的注释:
@RunWith(PowerMockRunner.class)
@SuppressStaticInitializationFor("some.package.ClassWithStaticInit")
在测试用例中:
Whitebox.setInternalState(Mappingloader.class, "filepath", testfilepath);
Mappingloader.loadMappingFile();
我也试图通过反射来改变这一点(使用Java反射改变私有静态最终字段),但它总是抛出FileNotFoundException为"filepath",不采取改变的路径"testFilePath"
是否有任何方法我可以改变这个变量,使它不抛出FileNotFoundException没有任何修改的源代码?
如果我在源代码中删除"throw new RuntimeException(e);", powermock将为我工作。但是我想在不修改源代码的情况下实现这一点,无论是通过powermock,反射api。
那么,您可以试试Powermock的运气;这应该是可行的(也许如果你花更多的时间阅读它的文档并进行实验);但老实说:你的问题不在于测试。您的问题是您创建了不可测试的代码。现在你正试图使用大的powermock锤子来"修复"你的破碎的设计。
你看,当使用static方法和常量时;人们认为他们"节省"了性能(这是真的;但在一个非常小的度;这对99.999%的应用程序来说可能并不重要);但是他们总是忘记使用静态会导致直接耦合不同的功能。static在良好的OO设计中是异常的;并应谨慎使用。
因此,在您的情况下,您可以将整个内容替换为以下内容:
interface MappingLoader {
Map<String, String> loadMappingsFrom(String fileName);
}
class MappingLoaderImpl implements MappingLoader {
...
,你看,突然之间你只处理"真正的"接口和类;以及非静态方法;令人惊讶的是:现在你可以对整个程序进行单元测试了;最有可能的是,您甚至不需要一个mock框架。你只需要在某个地方创建一个带有映射的临时文件;然后你要确保你的impl类给你那个文件的映射。零嘲笑;内部实现细节的零测试;只有几个断言。
和另一个优势:所有应该只有使用MappingLoader 接口的客户端代码也可以被测试。因为像EasyMock或Mockito这样的普通框架将允许您模拟出该接口的实例……因为:不再有静态调用了!
这就是改变私有final静态字段值的方法——不使用它们!
(如果我让你感到好奇:看看这篇文章,学习如何从头开始编写可测试的代码)
虽然我完全同意@GhostCat的回应,但我明白你正在寻找一个不涉及更改源代码的解决方案。您是否想过在测试运行之前更改/tmp/mapping.properties
的内容(并在之后恢复它们)?
static final String
字段或任何final static
原语字段不能在运行时修改。如果速度诚实,你可以修改这些字段,但你的改变不会影响代码使用这些字段,因为在编译期间引用被替换为值。
我的建议:使用static mock
Files.newInputStream()
调用,然后返回ByteArrayInputStream
与预期的数据。在这种情况下,您将避免可能影响测试稳定性的脆弱磁盘IO操作。