I work with spring profiles with several configurations (prod, dev, test ...). I'm using several property files such as "application-prod.properties", "application-dev.properties ...). At this point, everything's fine.
But now, I want to add a language management using the same system. I tried to add 2 languages, english and french. So I created 2 more property files : "application-fr.properties" and "application-en.properties". Then I tag main main language configuration class with :
#Profile({ "fr", "en"})
public class MyClass{
public static String MYVAR;
#Value("${myclass.myvar}")
private void setMyVar(String myVar) {
MYVAR = myVar;
}
}
With my config files being like :
myclass.myvar=...
My active dev profile is "dev,en" for example, and it doesn't set my vars.
Any idea how to fix my issue ?
I fixed my issue, my syntax was ok, it was an ordering problem with my class constructions. My config file was initialized too late.
Related
I am trying to configure my application.properties to take the value from the system variables I've set. The problem is that it won't work no matter what I do. I've tried using a custom class configuration with DataSource from this example still no success. All I was able to find on stackoverflow are links pointing to the official docs. Unfortunately that's a dead end since it doesn't say anything and there are no examples for what I'm trying to achieve. I also found examples like spring.datasource.url = ${SPRING_DATASOURCE_URL} and everyone is saying that spring will know how to automatically take the environment variables. Well surprise, it doesn't.
I also found examples like spring.datasource.password = ${SPRING_DATASOURCE_PASSWORD:the_actual_password) or spring.datasource.url = #{SPRING_DATASOURCE_URL:#{'the_actual_url'}} which is totally not what I need and it's pretty useless if you ask me. I mean I could achieve the same thing writing spring.datasource.password = the_actual_password. The whole point is to hide the sensitive data..
Now, this being said I'll leave 2 screenshots with what I have. The reason why I am trying to achieve this is because when I'll push to GitHub I won't have to worry that my credentials or anything will be out in the open for everyone to see.
Here is how my environment variables look like:
Here is how application.properties look like:
Thank you in advance! And in case you have an answer to my question could you also let me know how can I achieve the same thing with environment variable but for the application.jwt properties?
Ok, the solution was pretty... stupid, I suppose, but here it is. The reason why it didn't worked is because the environment variables were defined after IntelliJ first opened as described here. It seems like everything is working fine now.
I managed to achieve the functionality that I wanted.
In other words this:
spring.datasource.url = ${SPRING_DATASOURCE_URL}
spring.datasource.username = ${SPRING_DATASOURCE_USERNAME}
spring.datasource.password = ${SPRING_DATASOURCE_PASSWORD}
spring.datasource.driver-class-name = ${SPRING_DATASOURCE_DRIVERCLASSNAME}
Is now working perfectly.
Thank you for all your help!
Have you used the correct annotations?
Given Properties as such:
root.test = ${TEST.VAR:-Test}
Environment variable like:
TEST.VAR = Something
Configuration class:
#Configuration
#ConfigurationProperties(prefix = "root")
public class Test {
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}
You can use Records by setting #ConfigurationPropertiesScan on your Main class
#SpringBootApplication
#ConfigurationPropertiesScan
public class DemoApplication{...}
Defining Record like so:
#ConfigurationProperties(prefix = "root")
public record Test (String test) {
}
I am trying to create a unit test, however, whenever I run it I encounter null values on my variables. Debugging the issue points to my environment variables not being used globally on my unit test. As a class I'm testing calls another class that then references its values from an environment variable. How do I make use of global environment variables in IntelliJ?.
I've already added Environment Variables in the Test Configuration like this,
However, this doesn't seem to be used on the entire project. Hence classes calling this environment variables are returning null. How do I make my Unit Test and the classes it calls to use the globally declared environment variables?. TIA. Below is a snippet of my code of how my environment variables are being used in a class
#Value("${fintech.clientid}")
private String clientId;
#Value("${fintech.secret}")
private String clientSecret;
#Value("${digifi-host}")
private String fintechHost;
#Value("${fintech-digifi-login-endpoint}")
private String loginUrl;
#Value("${fintech-single-session-endpoint}")
private String singleSessionUrl;
What this does is from the Class, it calls the values stored in my application.properties file. And from the application.properties file, it tries to look for the proper values in the environment variables declared on run time.
So from Java Class > application.properties file/config > Runtime Environment Variables
Below is the screenshot of variables with null values when debugging the test. As you can see, all of the values are null which means it didn't load the environment variables I have put in the Unit Test. On the other test case where I had a temporary fix (as I put in the answer here), they are populated and hence loading the environment variables properly, but in my many other test cases like this one, it doesn't.
PS:
I've already found related articles in stackoverflow, but they are all test-class specific and that uses surefire plugins or setting the environment variables or via pom, but I don't need it to be there as it is a requirement for us to use environment variables on runtime as the values of the variables should be hidden and not visible on the code. I just simply need the entire project to use a global environment variable when it is doing its Unit Test. Much like how my project would use the environment variables I set in the IDE in normal runtime.
Just for Reference. I already did the ff.:
A.
#ClassRule
public final static EnvironmentVariables environmentVariables = new EnvironmentVariables().set("property1", "value1");
B.
#ContextConfiguration(locations = "classpath:application.properties")
public class LoginServiceTest {
...
}
C.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<environmentVariables>
<SERVER_PORT>8082</SERVER_PORT>
</environmentVariables>
</configuration>
</plugin>
D.
#TestPropertySource(properties = {"property1=value1","property2=value2",})
public class LoginServiceTest {
...
}
E.
public class LoginServiceTest {
static{
System.setProperty("property1", "value1");
System.setProperty("property2", "value2");
...
}
UPDATE:
This solution worked on all of my test. You can refer here for more details.
#RunWith(SpringRunner.class) //Add this
#SpringBootTest(classes = Application.class) //Add this
public class LoginServiceTest {
...
}
Then on
Run > Edit Configurations > Templates (in sidemenu) > JUnit
Then put all your environment variables here.
Click + on the Upper Left window & Apply.
Then delete all existing Unit Test command in your configuration and proceed to re-running all your test again plainly.
Then you'll see the environment variables being added automatically on all your new and upcoming unit test.
You won't have to manually add an environment variables to each unit test command alright as what I happen to do annoying before. Should you ever have an update on your environment variables. Delete the main unit test configuration you need to have an update, and update the JUnit Template instead so that changes will reflect to new unit tests that you may have.
PS:
Thing is, I still encountered the very same issue on some of my Unit
Test, that even though the environment variables are being read
properly on runtime and in some unit test alright with the above configurations. It is only during
the other many Unit Test the very same environment variables are not
being retrieved or received properly by the classes. At first I
thought my classes are not really getting the proper environment
variables and there must be something wrong as to how I stored the
environment variables in IntelliJ, which it did not really, but it
turns out this code format I have is the issue.
#Value("${fintech.clientid}")
private String clientId;
#Value("${fintech.secret}")
private String clientSecret;
#Value("${digifi-host}")
private String digifiHost;
It turns out,even though though this particular code works on runtime, it wont on Unit Test time, like ever.
Hence I tinkered with this particular codes until I was already able to get the proper environment variables on Unit Test. Refer to the changes from the code above to the one that fixed the issue for me below.
#Value("${fintech.clientid}")
public void getClientId(String tempClientId) {
clientId = tempClientId;
}
private String clientId;
#Value("${fintech.secret}")
public void getClientSecret(String tempClientSecret) {
clientSecret=tempClientSecret;
}
private String clientSecret;
#Value("${digifi-host}")
public void getDigifiHost(String tempDigifiHost) {
digifiHost=tempDigifiHost;
}
private String digifiHost;
I have a bit of code that looks like this:
#Value("#{systemProperties['TARGET_ENVIRONMENT']?: 'qa'}")
private String environment;
In my integration tests, this property is always blank, and I can't seem to do anything to give it definition. I tried doing something like this in my integration tests to simply override the target environment attribute to something else:
#Before
public void setUp(){
System.setProperty("TARGET_ENVIRONMENT", "I love dogs");
}
But that didn't really work out.
#Before
public void setUp(){
System.setProperty("TARGET_ENVIRONMENT", "qa"); -> Not I love Dogs
}
#Value("$peopleSearch{key}") -> Defined as per properties file
private String peopleSearch;
#Value("$peopleSearch{address}") -> Defined as per properties file
private String address;
But that doesn't really change anything. I have other properties (as above) which are being defined in properties files that work out ok and get values, but this one seems to be using the systemProperties attribute, which I have no idea how/where to modify. What do I do to override systemProperties attributes?
systemProperties isn't a function but variable. And it's initialized at the time Spring context is loaded. That's why setting system properties in runtime doesn't effect in your tests. Here you can find more details of SpringEL.
You can pass the system property -DTARGET_ENVIRONMENT to the runner of the test. For example, if you run the test in an IDE (Eclipse or IntelliJ), you can pass it under JVM arguments of the Run Configurations. Or if you run it by Maven, see this.
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/
i have a play 2.3 application that I want to test.
This application has a Global.java class that extends GlobalSettings in order to start a recurring Akka task every 5minutes.
During testing I don't want the task to be scheduled since it creates several issues and I don't need it.
Therefore I would like to override the GlobalSettings.
By reading the documentation, it looks like it should be possible to use a FakeApplication for that. However I tried to do that in several ways and the framework still runs my default global settings.
I created a base class for my tests that looks like this:
public class BaseTest
extends WithApplication
{
protected FakeApplication provideFakeApplication()
{
return fakeApplication(inMemoryDatabase("test"), new GlobalSettings());
}
}
According to the documentation, if a test class extends WithApplication a fake application should automatically start for me, with the configuration provided.
Disregarding if this happens or not, even before the testing methods are called, the default global settings trigger. The "new Global()" doesn't override the default.
I also tried to manually start the fakeApplication using a #BeforeClass annotation, with no success.
I am running the tests with the "activator test" command.
It looks like that the fakeApplication is indeed used for each test, but before even the first test starts, the main application is started and its global triggered. And that's what I don't want it to happen.
Am I doing something wrong or is it a bug in play? if it is a bug, is there a workaround?
EDIT: I just noticed that even the database settings don't get overridden correctly. I normally use a h2 file database for developing, but i want a inmemory, different one for testing. However by using the code above doesn't change the database used, and therefore my tests run against my file DB.
I also tried something like this:
#Test
public void testMyTest()
{
running(fakeApplication(inMemoryDatabase("test2")), () -> {
//TESTING CODE THAT USES DB
});
}
and still any query inside the body runs against the DB configured in the config file, not the inmemory database.
Edit
Chafik solution kind of worked for me, since by specifying a different config file in the build.sbt file I managed to override my settings. Things are still really wierd though:
1)Now if from my fakeApplication constructor I try to override the GlobalSettings by passing a new instance in helper method, the settings are correctly overridden, while before I could not at all override the main one
2)If I revert my change and don't supply a test conf file, I can still override the globalsettings. That is, the behaviour is different than it used to be initially.
Something is definitely strange around the test command, its configuration, running scope, and the way fakeApplication override the configuration, and/or the documentation about it si definitely unclear and lacking. However since at least I achieved what I wanted to do I'll still consider the answer solved.
I did what you want like this.
Set a different config file for testing in your build.sbt
javaOptions in Test += "-Dconfig.file=conf/application.test.conf"
Create conf/application.test.conf
Include main configuration file at the beginning include "application.conf"
Override the settings that you want
Create a property like this startAkkaActor=true in the main config file
Create a property like this startAkkaActor=false in the test config file
Update you Global.java where you start your Akka actor
if (Play.application().configuration().getBoolean("startAkkaActor")) {
// Start your Akka actor
}
You can do the same with your database settings
The config file must be defined in build.sbt because Play forks JVM for each test without duplicating the parameters set in the main JVM. The following does not work :
activator test -Dconfig.file=conf/application.test.conf