There is a java class, it is based on Singleton pattern. how to do unit test for this class? the following is my related code:
public class ConfigFromFile implements ConfigStrategy {
private String endpoint;
private final static String CONFIG_FILE = "/conf/config.properties";
private InputStream getInputStream(String configFilePath) throws FileNotFoundException{
return new FileInputStream(configFilePath);
}
private void initFromFile() {
Properties prop = new Properties();
InputStream input = null;
try {
input = getInputStream(CONFIG_FILE);
prop.load(input);
endpoint = prop.getProperty("endpoint");
} catch(Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
}
}
}
}
private ConfigFromFile() {
initFromFile();
}
private static class ConfigFromFileHolder {
private static ConfigFromFile instance = new ConfigFromFile();
}
public static ConfigFromFile getInstance() {
return ConfigFromFileHolder.instance;
}
@Override
public String getEndpoint() {
return endpoint;
}
}
I need to write unit test for this class.
- the unit test can't call the external resource, so we need to mock call "/conf/config.properties" file. we can use jmockit.
- this class is based on Singleton pattern. We hope that the interaction between the two cases can not be affected.
The following is my case:
- Case1, it is normal case, the file content is "endpoint=www.baidu.com"
- Case2, it is an abnormal case, we can mock this file does not exist.
how to implement these cases? Thanks!
You can add a package-scope constructor that takes in the path of the file to load, and have your test create a fake file in a temporary folder, and then create an instance of your test, passing in the path to the file. No mocking necessary.
Note I rewrote
initFromFile()
to use try-with-resources, which you can do if if you are using JDK 7 or above.You might want to reconsider whether this class needs to be a static singleton. It not only makes the code harder to test, but it can't be configured to use different files in different environments. Remember that the test for a class is the class's first user of the API. If your test is hard to write, that can indicate problems with your API.
If you need to restrict to one instance, I suggest using a dependency injection framework like Guice or Spring. If you use Spring, your class can implement
InitializingBean
and load the configuration file after the class is constructed but before it is injected into another class:Yes, that's all the code you need.
getEndpoint()
check if the initialization failedYou can do something similar with Guice.
But wait, if you use Spring, and you are willing to move the endpoint value into the Spring configuration, then it gets even simpler!
The class is so simple, it doesn't need any unit tests.
Your bean XML would look like this:
Of course, at this point I would get rid of
ConfigStrategy
and set the configuration on the object that uses the configuration.