I need to run project tests both locally and automatically on TeamCity server.
Local test execution must use local database connection, and when run on TeamCity, tests must use a remote connection to the database.
So I need to tell my tests, when to use local connection and when to use remote and pass URL, username and password in this case.
To tell that I decided to use java system properties. I found built-in support in Gradle for that
systemProperty 'some.prop', 'value'
The question is, how can I create a standard test task for local test run, that will not pass any properties, and a custom test task, that will set system properties before run?
I tried something like
task teamCityTest(type : Test) {
scanForTestClasses = false
includes = ['**/*Test.class']
systemProperty 'some.prop', 'value'
}
but it failed with NPE, that means I'm doing something wrong.
The approach is fine (you can use the Java plugin's test task for running tests locally), but you'll have to configure further properties for teamCityTest such as classpath = configurations.testRuntime (or even classpath = test.classpath). For a full example, see samples/java/withIntegrationTests in the gradle-all distribution.
Related
We set several key/value pairs in our gradle.properties file. (eg LOGIN_UID, LOGIN_PWD)
We can successfully reference them in our build.gradle (eg $LOGIN_UID) and our JUnit tests (eg System.getProperty("LOGIN_UID") when running gradle test from the cmdline.
However when clicking on a Run Test codelens within a JUnit's Java file within VSCode gradle.properties are not passed in. Guessing the Gradle test task is not being executed?
Greatly appreciate it if someone can help us understand and solve this running from a codelens.
Basically what you need is to add a setting in VS Code, something like this:
{
"java.test.config": {
"vmArgs": ["-DLOGIN_UID=id", ...]
}
}
Then test runner will pick up them and pass the properties to JVM.
At last, the configuration can be persisted in your workspace's .vscode/settings.json. If the properties have any sensitive data, like password, don't commit them to the source control!
I'm building a Java desktop application, using JavaFX, Gradle, javafx-gradle-plugin. This application connects to a server that I also build. When I compile a release version, running gradle jfxNative, I want it to talk to the production server; but otherwise, I want it to talk to localhost.
What's the proper Java/Gradle way of handling this? Some sort of compilation profile?
You can use Gradle's source sets for this:
Sample build.gradle:
apply plugin: 'java'
sourceSets {
prod {
java {
srcDirs = ['src/main/java', 'src/prod/java']
}
}
dev {
java {
srcDirs = ['src/main/java', 'src/dev/java']
}
}
}
task devJar(type: Jar) {
from sourceSets.dev.output
manifest {
attributes("Main-Class": "MyPackage.MyClass")
}
}
task prodJar(type: Jar) {
from sourceSets.prod.output
manifest {
attributes("Main-Class": "MyPackage.MyClass")
}
}
Now you can create two configuration classes for your dev and prod versions:
src/dev/java/MyPackage/Configuration.java
src/prod/java/MyPackage/Configuration.java
All the common code will be in the main source set:
src/main/java/MyPackage/MyClass.java
MyClass can get some values from the configuration class (e.g. Configuration.getBaseUrl())
Running gradle devJar/ gradle prodJar builds one of the variants.
Note: you may need to extend jfxNative/jfxJar instead of Jar in your case.
The simplest solution: Have a configuration file containing such information.
You either compile it into the application as a java resource or place it next to the jar file so it can be easily looked up via the filesystem.
With gradle all you need to do is define two build tasks with different input properties and insert the values into your properties file with groovy templating.
application.properties in src/main/resources:
server.address=${serverAddress}
add to your build.gradle
task setProductionServerAddress {
processResources.expand([serverAddress: "https://app.example.com/v1"])
}
jfxJar.dependsOn(setProductionServerAddress)
jfxNative.dependsOn(setProductionServerAddress)
And then on the application:
Properties properties = new Properties();
properties.load(getClass().getResourceAsStream("/application.properties"));
if (properties.getProperty("server.address").equals("${serverAddress}")) {
setUrl("http://localhost:8080/v1");
} else {
setUrl(properties.getProperty("server.address"));
}
Have it check environment variables for names of configuration files. Nothing to do with gradle or build. The same program should run properly wherever it is deployed.
See, e.g., Properties for dev and production
The easiest approach is to define a system property which specifies where the file system location for your data is. The production appserver would define one value (using java -D in the startup script), and your dev app server would define another value. Your application source would consult the system property value (using System.getProperty()) to discover the appropriate location
Also, this makes sense.
Put the information you need in JNDI - that's what it is designed for.
Consider letting your application refuse to do anything if the information is not there.
Another reference: What is the best way to manage configuration data
EDIT: Well, what you're asking is logically not possible then, it seems to me. "It should connect to production, unless a specific someone wants to connect to development, but that feature should only be available to unknown persons" The start menu is only a shortcut for running the application, so you can install a "dev" shortcut with command line settings that are read as environment vars.
I would go with the one of the "12 factor app" concept which can be read here
One of its main concept is to use system environment variable which should determine whether you are working on a prod or dev or qa env etc.
each project/environment/machine should contain its relevant env property, which after then can be retrieved through the gradle process similar to maven profile plugin.
An example for how to detect:
`if (project.hasProperty('env') && project.getProperty('env') == 'prod') {
apply from: 'gradle/production.gradle'
} else {
apply from: 'gradle/development.gradle'
}`
more on this approach using gradle can be found: gradle profile
In my opinion and like others have suggested, this has little to do with the build and more to do with Run Time.
Therefore you could resort to checking for some kind of run time flag - a convenient and often used approach is to use System Properties.
On your Dev box, you could set an Environment variable - lets say FX _DESKTOP_APP_ENV = DEV or some such.
From your code you can look this up and decide the URL you want to use.
String env = System.getenv("FX _DESKTOP_APP_ENV");
String url = env == null ? "Production" : env;
On windows systems you can set up your system environment variables like so -- enter link description here
On *nix systems enter link description here
Hope this helps
You need to pick a configuration scheme (if JavaFX doesn't pick one for you).
I like https://github.com/typesafehub/config .
The config library will have instructions on how to make your "production" config differ from your "development" config.
See also JavaFX:Editable Configuration Files After Packaging
What's the proper Java/Gradle way of handling this? Some sort of compilation profile?
No, I would strongly recommend against compiling different code for production v.s. test. It will invalidate your testing. This should be handled in configuration, not in code. The conventional Java way of doing this is with configuration files (which can be compiled into the JAR as resources).
How to do this with Typesafe Config
I've had a bit of a look, and I am surprised not to find a good quality tutorial I can link you to here, sorry (I found a few rubbish ones). Perhaps this question will become a reference for others.
I would do something like this:
Create a "dev" and "prod" config files, along the lines of https://stackoverflow.com/a/33261928/8261
Arrange for your app to use the "dev" config file when running in your IDE and "prod" config file when running from a compiled JAR, as per Can you tell on runtime if you're running java from within a jar?
My guess as to why there aren't many tutorials for this is that all application or web Frameworks handle this for you.
I have a Windows 7 and I am testing an Android Native app using Appium using Java. The framework used is TestNG. I would like to use Jenkins for running smoke testing for builds available in Jenkins. My desired capabilities are listed in #Before. Can we dynamically paremetrize all of the following in Jenkins?
“automationName”
“platformName”
“platformVersion”
“deviceName”
“app”
“appPackage”
“appActivity“
If so How?
Now if I dynamically parametrize, what would happen to the desired capabilities in my script #Before
its quite simple,
in your class you have to include the code which will listen for input from jenkin job.
String deviceName = PropertyUtils.getProperty("deviceName");
and while you configure your job in Jenkins you have to include string parameter like the image below,
and while building, pass the parameter you want for each build,
The value which you passing above will be processed in your code.
I have a Java TestNG project set up with gradle running test suites. Currently, most of the tests are pulling certain parameters out of a constants.properties file. How would I modify these on the command line when running the gradle task? Will gradle -DapplicationKey=0000 replace the line applicationKey=1234 in my constants.properties file?
Edit:
To be a bit more clear about the situation and the question, my constants.properties file contains around 400 to 500 properties that are already defined. I would like to avoid rewriting those properties in gradle completely. I just want to override those properties from the command line when Jenkins runs the same commands as part of that build job.
You want to pass system properties to the JVM used to run tests. Here is a way to configure all tasks of type Test:
tasks.withType(Test) {
systemProperty 'applicationKey', System.getProperty('applicationKey', '1234')
}
or just one task
test {
useTestNG()
systemProperties = [
applicationKey: System.getProperty('applicationKey', '1234')
]
}
You can also copy all system properties from the Gradle environment to the child virtual machine with systemProperties = System.getProperties()
I have extracted all my integration tests out of my multi-module setup and put them all into a separate project. These integration tests are based on spring and a use a real database. I am using dbmaintain which is a database versioning tool, it automatically tracks which SQL files need to be applied and keeps the database in a correct state.
What I would like is to be able to run the code that ensures the database is up to date before any test is run. So if you run all the tests (from Eclipse or Maven in my case) that it will first perform the db check once, or if you run a single test it will first perform the db check. No matter how many tests are run, it should always run the db check.
Right now I am thinking that I will use #BeforeClass in the base test class (all tests ultimately extend from this class) which will instantiate a singleton to do it's work. That singleton will control everything to make sure things only get run once.
I am hoping there is a cleaner way.
By default, the Maven runner for JUnit reserves the right to reorder tests. This is actually a Good Thing(tm), because you can tell the Maven JUnit plugin to run tests in parallel, which means you wouldn't know the order anyways. In addition, other tools (like TeamCity) can be set to run failing tests first.
I think your best bet would be to add your DB update code as part of the test suite setup (not part of your JUnit framework). Use the Exec Maven Plugin to call your DB code, binding it to the generate-test-resources phase. You'll want to make sure that when you run your tests, you actually call Maven to run the test.
JUnit does have the concept of an ExternalResource, which is a more explicit way of declaring the database dependency. It would be a few more lines of code than the base class, but depending on your perpective it may be more elegant.
Within Maven:
(1) Add the dbmaintain plugin: http://source.mysema.com/display/maven/Maven+Plugins
(2a) Call the appropriate goal (e.g. updateDatabase) explicitly before calling test
(2b) Or, if you want the dependency to be executed during a specific phase, then maven supports this, too: http://maven.apache.org/plugins/maven-dependency-plugin/usage.html
Then, you can connect Eclipse to these Maven changes:
How do I start Maven "compile" goal on save in Eclipse?
JUnit doesn't support test ordering. You will need to use TestNG for this. For example:
#Test(groups = "init")
public void initDatabase() { ... }
#Test(dependsOnGroups = "init")
public void test1() { ... }
#Test(dependsOnGroups = "init")
public void test2() { ... }
In this example, initDatabase() will be run first, and only if it succeeds will test1() and test2() be run. If initDatabase() fails, test1() and test2() will not run and they will be marked as "skipped" in the report.
Note also that you can add methods to any group at any time and the dependencies will keep working the way you expect them.