While writing unit tests for a small component that is part of a relatively massive Java Project, I came across the need to use a method in another class TheOtherClassNoPartOfMyProject that will access a .properties file to fetch values used to set up SSLContext. I managed to get the JAR dependency for this class and attached the source code. Luckily, I can debug the other class which is not part of the component I am developing. Eventually, the method executes the following steps:
public class TheOtherClassNoPartOfMyProject {
...
...
private ResourceBundle resourceBundle = null;
...
...
public void setLocale(Locale newLocale) throws ACCatastrophicException {
if (newLocale.equals(locale) && (resourceBundle != null)) {
return;
}
locale = newLocale;
try {
resourceBundle = ResourceBundle.getBundle(filename, locale);
} catch (MissingResourceException e) {
resourceBundle = null;
System.out.println("Could not locate properties file for locale '"
+ locale.toString() + "'");
throw new ACCatastrophicException("Could not locate "
+ ACProductVersion.getProductName()
+ " properties file for locale '" + locale.toString() + "'");
}
}
...
...
}
The class TheOtherClassNoPartOfMyProject encapsulates the built-in Java Type ResourceBundle to work with .properties files.
When the test runs, I get the error Could not locate properties file for locale ....
Below is to give more context to the problem I am facing.
The component I am writing needs to create SSLContext and must reuse existing common classes I am facing difficulty in how to reuse such classes while writing unit tests since not all dependencies and required properties files are available for the component I am writing.
I have a valid .properties file which works when deployed under the bin folder of the application root folder of the installed application. However, during development time, I don't have a bin folder in my Maven Project and am not sure where to put this .properties file. Below is the code part to create SSLContext in my Maven Project, class MyService:
public class MyService {
...
private static SSLContext sslContext=null;
private static final String TLSV12 = "TLSv1.2";
...
public void createSSLContext() {
KeyStore keyStore= null;
KeyStore trustStore = null;
InputStream kis =null;
InputStream tis = null;
KeyManagerFactory keyManagerFactory = null;
TrustManagerFactory trustManagerFactory = null;
try {
constants = TheOtherClassNoPartOfMyProject.getInstance();
sslContext = SSLContext.getInstance(TLSV12);
if (constants.getString("webservice.keystore") != null && !(constants.getString("webservice.keystore").isEmpty())) {
keyStore = KeyStore.getInstance("JKS");
kis = new FileInputStream(constants.getString("webservce.keystore"));
if (constants.getString("webservice.keystore_password") != null && !(constants.getString("webservice.keystore_password").isEmpty())) {
String keyPassword = "changeit";
keyStore.load(kis,keyPassword.toCharArray());
keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyPassword.toCharArray());
}
}
if (constants.getString("webservice.truststore") !=null && !(constants.getString("webservice.truststore").isEmpty())) {
trustStore = KeyStore.getInstance("JKS");
tis = new FileInputStream(constants.getString("webservice.truststore"));
if (constants.getString("webservice.truststore_password") != null && !(constants.getString("webservice.truststore_password").isEmpty())) {
String trustStorePassword = "changeit";
trustStore.load(tis, trustStorePassword.toCharArray());
}
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
}
sslContext.init(
keyManagerFactory!=null?keyManagerFactory.getKeyManagers():null,
trustManagerFactory!=null?trustManagerFactory.getTrustManagers():null,
new java.security.SecureRandom());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I was thinking to use mockito to mask such methods, but first I wanted to ensure that the code I am writing will work with the existing dependencies. Also, I still need to research how to use mockit.
Where should I put the .properties file so that it can be picked up by ResourceBundle.getBundle()?
I figured out that I must place the file under
src/test/resourceorsrc/main/resources. Also, if you don't qualify the resource name with a package name, then it will look for the file in the base folder of the compiled classes such astarget/test-classes. If you qualify the resource name with a package name, it will look for the file in the related folder matching the package name. Note that the file is copied to the relevant folder in the undertarget/during compile time.You can add this test to quickly verify how it works:
Since the above code is running from the test folders, you can place the file under
src/test/resource/com/fun/resourcesand name itSVCInterface.propertiesand it will work. Make sure it has the keysome.key=some-value. In Eclipse, it works since when you run the tests, it will include the target folder of the compiled classes in the classpath by default.