I have written a simple java.util.Properties
wrapping class. Unfortunately, in my opinion, it isn't testable at the moment and I don't have any idea how to improve it. I could use PowerMockito to change properties
after loading, or add a setter for them, or inject some class that provides properties
, but I don't like any of that. I would like to avoid exposing properties
by making it public or by getter/setter.
My application details:
- Spring boot
- my class is injected by
@Bean
mechanic CONF_FILE_NAME
containskey=value
formatted properies with names same as inKeys
subclass.
I would like to unit-test logic in this class (both public method) without relying on values in file.
PropertiesManager.java
:
package pl.propertiesdemo;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;
public class PropertiesManager
{
private final String secretToken = "SECRET";
public final class Keys
{
public final static String KEY1 = "KEY1";
public final static String KEY2 = "KEY2";
}
private final String CONF_FILE_NAME = "conf_file.conf";
private Properties properties;
public PropertiesManager() throws IOException
{
properties = new Properties();
InputStream in = new FileInputStream(CONF_FILE_NAME);
properties.load(in);
}
public String getProperty(String name)
{
String property = properties.getProperty(name);
if (property == null) {
System.out.println("Property " + name + " not found in properties file");
}
return property;
}
public HashMap<String, String> getAllPublicProperties()
{
HashMap<String, String> map = new HashMap<>();
properties.keySet().stream().map(f -> (String)f).filter(f -> !f.contains(secretToken)).forEach(f -> map.put(f, properties.getProperty(f)));
return map;
}
}
PropertiesDemo.java
: (main
method and usage of both public methods)
package pl.propertiesdemo;
import java.io.IOException;
public class PropertiesDemo
{
public static void main(String[] args) throws IOException
{
PropertiesManager manager = new PropertiesManager();
System.out.println(manager.getProperty(PropertiesManager.Keys.KEY1));
System.out.println(manager.getAllPublicProperties());
}
}
conf_file_conf
: (file loaded by PropertyManager
)
KEY1=value_of_key1
KEY2=value_of_key2
PropertiesManager.java
: (JUnit
test I have so far)
package pl.propertiesdemo;
import java.io.IOException;
import java.util.HashMap;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class PropertiesManagerTest extends TestCase
{
public PropertiesManagerTest(String testName)
{
super(testName);
}
public static Test suite()
{
return new TestSuite(PropertiesManagerTest.class);
}
private PropertiesManager getPropertiesManager()
{
PropertiesManager prop = null;
try {
prop = new PropertiesManager();
} catch (IOException ioe) {
fail();
}
return prop;
}
public void testGetProperty()
{
PropertiesManager prop = getPropertiesManager();
String value = prop.getProperty(PropertiesManager.Keys.KEY1);
assertEquals("value_of_key1", value);
}
public void testGetAllProperties()
{
PropertiesManager prop = getPropertiesManager();
HashMap<String,String> values = prop.getAllPublicProperties();
assertTrue(values.size() > 0);
assertEquals(0, values.keySet().stream().filter(k -> k.contains("SECRET")).count());
}
}
I don't like my tests, because right now they are dependant of value in real configuration file.