I'm struggling to create a test to verify a ServletListener that loads a properties file. I've tested when running the application that it works fine and it finds the file in the classpath. But I don't know how to create a test for it. My idea is to create a temp file with a test property and then verify the property is put into the System properties. But I always fail to create the file in the right place.
I've tried creating the file in /target/test-classes or directly in the root of the application but it never finds it. Any idea?
This is the code I'm trying to test:
public class PropertyReadingListener implements ServletContextListener {
public static final String PROFILES_PROPERTIES = "profiles.properties";
#Override
public void contextDestroyed(ServletContextEvent event) {
}
#Override
public void contextInitialized(ServletContextEvent event) {
Properties propsFromFile = new Properties();
try {
propsFromFile.load(getClass().getResourceAsStream(PROFILES_PROPERTIES));
} catch (final Exception e) {
log.warn("Unable to find {}, using default profile", PROFILES_PROPERTIES);
}
propsFromFile.stringPropertyNames().stream()
.filter(prop -> System.getProperty(prop) == null)
.forEach(prop -> System.setProperty(prop, propsFromFile.getProperty(prop)));
}
}
Thanks.
Assuming that you are using maven, put your properties file here:
src/test/resources/foo.properties
The maven resources plugin will place the (possibly filtered) copy of the file in
target/test-classes/foo.properties
The test-classes directory is on the classpath, so you reference the file like this (note the slash in front of the file name):
... getResourceAsStream("/foo.properties");
Where is getResourceAsStream("file") searching when running from a test?
Assuming that you are talking about JUnit ....
Unless you have done something funky, your unit tests will be loaded by the default classloader, and that means that the normal JVM classpath with be searched.
(Junit 4 allows you to use a different classloader: see https://stackoverflow.com/a/9192126/139985)
But I always fail to create the file in the right place.
It seems that your real problem is understanding how the Java classpath and classpath searching works. If you understand that (and you know what JUnit runner's actual classpath is) then it should be obvious where to put the properties file so that the classloader can find it.
See Different ways of loading a file as an InputStream
Basically when you do a getClass().getResourceAsStream it looks in the package of that class for the file.. so if your PropertyReadingListener is in com.company.listeners.PropertyReadingListener then it will look in com/company/listeners for the property file.
For testability, I would pass in an InputStream into the listener that way the test can create the input stream in a convienent way and the actual user of the class in code can pass in the InputStream returned from getResourceAsStream
Related
In my application I have two feature files:
processing.feature
copy.feature
For these I have two step definition files:
Processing Feature:
public class ProcessingFeature {
#Qualifier("moverA")
#Autowired
private IFileMover mover;
#Given("check file is available")
public void load() {
}
#When("the file is there at the location")
public void moveFile() {
output= mover.move(info);
}
}
Copy Feature:
public class CopyFeature {
#Qualifier("moverB")
#Autowired
private IFileMover mover;
#Given("check file is available")
public void load() {
}
#When("the file is there at the location")
public void moveFile() {
output= mover.move(info);
}
}
In both my feature files, I run check file is available as #Given step. My first question is, they are identical step definitions sitting in both step def file. What is the correct pattern so this code is not duplicated and both features can make use of it?
Secondly, both features run the file is there at the location but one uses MoverA & the Other uses MoverB. But the idea remains same. Again I don't like the duplication so how best can I re-use maybe through some abstraction ?
Ofcourse I get cucumber.runtime.DuplicateStepDefinitionException: Duplicate step definitions exception but I am curious to see what is correct pattern to solve these kind of problems
Steps can only be defined once. Step definitions are global, and not specific to a scenario or feature. Since a step can only have one definition, code duplication is not an issue.
You need to read the following page from Cucumber : https://cucumber.io/docs/gherkin/step-organization/
It will help you organize correctly your glue code.
As Greg said, the step definitions are global, it is an anti-pattern to create feature-specific steps :
https://cucumber.io/docs/guides/anti-patterns/#feature-coupled-step-definitions
In your feature file, I think there is a confusion between When steps (action : ie copying the file or processing the file) and Then steps (expected result : the file should be at which location).
Your step definitions should be more like :
#When("I copy the following file:(.*)")
public void copyFile(String fileName) {
xxxx calling system under test xxxx
}
#When("I process the following file:(.*)")
public void processFile(String fileName) {
xxxx calling system under test xxxx
}
#Then("the file is at the following location:(.*)")
public void checkFileExistence(String fileLocation) {
Assert.assertTrue(xxxxx);
}
To share state between steps, you can use the World object pattern :
cf https://cucumber.io/docs/cucumber/state/
This is downside when using plain text file and step mapping for BDD implementation. Alternate to this and similar issues because of additional feature file layer is, using pure java implementation of scenario. It will eliminate extra layer of feature files and certainly step definition files and allows you to follow behavior driven development.
I have a jUnit Test that has its own properties file(application-test.properties) and its spring config file(application-core-test.xml).
One of the method uses an object instantiated by spring config and that is a spring component. One of the members in the classes derives its value from application.properties which is our main properties file. While accessing this value through jUnit it is always null. I even tried changing the properties file to point to the actual properties file, but that doesnt seem to work.
Here is how I am accessing the properties file object
#Component
#PropertySource("classpath:application.properties")
public abstract class A {
#Value("${test.value}")
public String value;
public A(){
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public A(String text) {
this();
// do something with text and value.. here is where I run into NPE
}
}
public class B extends A {
//addtnl code
private B() {
}
private B(String text) {
super(text)
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:META-INF/spring/application-core-test.xml",
"classpath:META-INF/spring/application-schedule-test.xml"})
#PropertySource("classpath:application-test.properties")
public class TestD {
#Value("${value.works}")
public String valueWorks;
#Test
public void testBlah() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
B b= new B("blah");
//...addtnl code
}
}
Firstly, application.properties in the #PropertySource should read application-test.properties if that's what the file is named (matching these things up matters):
#PropertySource("classpath:application-test.properties ")
That file should be under your /src/test/resources classpath (at the root).
I don't understand why you'd specify a dependency hard coded to a file called application-test.properties. Is that component only to be used in the test environment?
The normal thing to do is to have property files with the same name on different classpaths. You load one or the other depending on whether you are running your tests or not.
In a typically laid out application, you'd have:
src/test/resources/application.properties
and
src/main/resources/application.properties
And then inject it like this:
#PropertySource("classpath:application.properties")
The even better thing to do would be to expose that property file as a bean in your spring context and then inject that bean into any component that needs it. This way your code is not littered with references to application.properties and you can use anything you want as a source of properties. Here's an example: how to read properties file in spring project?
As for the testing, you should use from Spring 4.1 which will overwrite the properties defined in other places:
#TestPropertySource("classpath:application-test.properties")
Test property sources have higher precedence than those loaded from the operating system's environment or Java system properties as well as property sources added by the application like #PropertySource
I faced the same issue, spent too much calories searching for the right fix until I decided to settle down with file reading:
Properties configProps = new Properties();
InputStream iStream = new ClassPathResource("myapp-test.properties").getInputStream();
InputStream iStream = getConfigFile();
configProps.load(iStream);
If you are using a jar file inside a docker container, and the resource properties file, say application.properties is packaged within the same classes directory that contains the java(this is what IntelliJ IDE does automatically for resources file stored in /src/main/resources), this is what helped me:
public static Properties props = new Properties();
static {
try {
props.load(
Thread
.currentThread()
.getContextClassLoader()
.getResourceAsStream("application.properties")
);
} catch (Exception e) {
e.printStackTrace();
}
}
Most other methods either only worked inside the IDE or inside the Docker. This one works in both.
if you want to load a few properties, I found a good way in the spring
ReflectionTestUtils.
#Before
Public void setup(){
ReflectionTestUtils.setField(youclassobject, "value", "yourValue")
}
>you can follow this link as well for more details https://roytuts.com/mock-an- autowired-value-field-in-spring-with-junit-mockito/
This surely is a common problem. I have a properties file like my-settings.properties which is read by an application class. When I write a test class, it needs to test different scenarios of things that could be present in my-settings.properties in order to ensure maximum code coverage (e.g. empty properties file, basic properties file etc). But I can only have one my-settings.properties in my src/test/resources.
What would be really great is if there was just some annotation
#MockFileOnClassPath(use = "my-settings-basic.properties", insteadOf = "my-settings.properties")
Then I could just have multiple my-settings-XXX.properties files in my /src/test/resources and just annotated the correct one on each test method. But I can't find anything like this. I'm using JUnit 4.12.
I can think of a couple of crude solutions:
Before each test, find the file on the file system, copy it using filesystem I/O, then delete it again after the test. But this is clumsy and involves a lot of redundancy. Not to mention I'm not even sure whether the classpath directory will be writable.
Use a mocking framework to mock getResource. No idea how I would even do that, especially as there are a million different ways to get the file (this.getClass().getResourceAsStream(...), MyClass.class.getResourceAsStream(...), ClassLoader.getSystemClassLoader().getResourceAsStream(...) etc.)
I just think this must be a common problem and maybe there is already a solution in JUnit, Mockito, PowerMock, EasyMock or something like that?
EDIT: Someone has specified that this question is a duplicate of Specifying a custom log4j.properties file for all of JUnit tests run from Eclipse but it isn't. That question is about wanting to have a different properties file between the main and test invocations. For me I want to have a different properties file between a test invocation and another test invocation.
I find that whenever dealing with files, it's best to introduce the concept of a Resource.
eg:
public interface Resource {
String getName();
InputStream getStream();
}
Then you can pass the resource in via dependency injection:
public class MyService {
private final Properties properties;
public class MyService(Resource propFile) {
this.properties = new Properties();
this.properties.load(propFile.getStream());
}
...
}
Then, in your production code you can use a ClasspathResource or maybe a FileResource or URLResource etc but in your tests you could have a StringResource etc.
Note, if you use spring you already have an implenentation of this concept. More details here
You can change your Service class to accept the name of the resource file, then then use that name to load the resource.
public class MyService {
public MyService(String resourceFileName){
//and load it into Properties getResourceAsStream(resourceFileName);
}
}
I create simple java class and export it to jar:
package test;
public class Test {
public Test() {
// TODO Auto-generated constructor stub
}
}
Jar file add to lib folder in Pentaho (there are many jar files)
Next step I want to use my class in Pentaho Data Integration so I created User Defined Java Class:
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
test.Test t = new test.Test();
return true;
}
When I click Test class I get the following information:
Line 3, Column 12: Class "test.Test" not found
So I have a question: Where is the mistake and why is the class not found?
Try checking the launcher.property file inside the /design-tools/data-integration/launcher folder. Make sure that the classpath and the libraries are having the path of the jar defined. Since you have placed your JAR file inside the lib folder, look for that.
Restart the Spoon after editing and it would work ideally.
I have placed the code inside the libext folder, so i have added :../libext to the classpath and libraries. And below is the code snip:
In case it still throws an error, try checking the Java code again. I assume something might have gone wrong there.
Also documented the above in here.
Hope it helps :)
I have JUnit tests that need to run in various different staging environments. Each of the environments have different login credentials or other aspects that are specific to that environment. My plan is to pass an environment variable into the VM to indicate which environment to use. Then use that var to read from a properties file.
Does JUnit have any build in capabilities to read a .properties file?
It is usually preferred to use class path relative files for unit test properties, so they can run without worrying about file paths. The path may be different on your dev box, or the build server, or where ever. This will also work from ant, maven, eclipse without changes.
private Properties props = new Properties();
InputStream is = ClassLoader.getSystemResourceAsStream("unittest.properties");
try {
props.load(is);
}
catch (IOException e) {
// Handle exception here
}
putting the "unittest.properties" file at the root of the classpath.
java has built in capabilities to read a .properties file and JUnit has built in capabilities to run setup code before executing a test suite.
java reading properties:
Properties p = new Properties();
p.load(new FileReader(new File("config.properties")));
junit startup documentation
put those 2 together and you should have what you need.
//
// Load properties to control unit test behaviour.
// Add code in setUp() method or any #Before method (JUnit4).
//
// Corrected previous example: - Properties.load() takes an InputStream type.
//
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
Properties p = new Properties();
p.load(new FileInputStream( new File("unittest.properties")));
// loading properties in XML format
Properties pXML = new Properties();
pXML.loadFromXML(new FileInputStream( new File("unittest.xml")));
This answer is intended to help those who use Maven.
I also prefer to use the local classloader and close my resources.
Create your test properties file, called /project/src/test/resources/your.properties
If you use an IDE, you may need to mark /src/test/resources as a "Test Resources root"
add some code:
// inside a YourTestClass test method
try (InputStream is = loadFile("your.properties")) {
p.load(new InputStreamReader(is));
}
// a helper method; you can put this in a utility class if you use it often
// utility to expose file resource
private static InputStream loadFile(String path) {
return YourTestClass.class.getClassLoader().getResourceAsStream(path);
}
If the aim is to load a .properties file into System Properties, then System Stubs (https://github.com/webcompere/system-stubs) can help:
The SystemProperties object, which can be used either as a JUnit 4 rule to apply it within a test method, or as part of the JUnit 5 plugin, allows setting properties from a properties file:
SystemProperties props = new SystemProperties()
.set(fromFile("src/test/resources/test.properties"));
The SystemProperties object then needs to be made active. This is achieved either by marking it with #SystemStub in JUnit 5, or by using its SystemPropertiesRule subclass in JUnit4, or by executing the test code inside the SystemProperties execute method.