Trying to understand Gradle documentation (Dependency configurations) about testRuntime


(Manuel Jordan) #1

Hello Gradle developers

I am woking with a Spring/Gradle multi-module project:

To run a test for a specific module I have the following:

project(':web-27-repository-jdbc') {
	description 'Repository JDBC'
	dependencies {
 	   compile project(':web-27-repository-api')
 	   testCompile project(':web-27-config')
 	   testRuntime project(':web-27-config') 	   
	}
}

Note: It works.

My confusion is about the following:

According with:
7.3. Dependency configurations
it says:

testRuntime

    The dependencies required to run the tests. By default, also includes the compile, runtime and test compile dependencies. 

Check the second part:

By default, also includes the compile, runtime and test compile dependencies

It says testRuntime includes compile, runtime and testCompile

Therefore I am assuming that:

dependencies {
 	   compile project(':web-27-repository-api')
 	   testCompile project(':web-27-config')
 	   testRuntime project(':web-27-config') 	   
	}

is the same than (it assuming that testRuntime includes testCompile - it according with the explanation shown above):

dependencies {
 	   compile project(':web-27-repository-api')
 	   //testCompile project(':web-27-config')
 	   testRuntime project(':web-27-config') 	   
	}

But not. I must declare two lines.

Until here
Question 01: What does really mean/refer the explanation?

I must assume that the explanation aims to other point. But what?

Even more when in:
45.5. Dependency management
the table shown that testRuntime extends runtime and testRuntime

Assuming that both lines are mandatory

testCompile project(':web-27-config')
testRuntime project(':web-27-config')

Question 02:

Is possible declare

testCompile project(':web-27-config')
testRuntime project(':web-27-config')

in just one line? something like (the following is not valid):

testCompile,testRuntime project(':web-27-config')

Thanks in advance


(James Justinic) #2

Based on your example, you are thinking about the configuration inclusions backwards.

If testRuntime includes compile, runtime, and testCompile, that means that anything added to testCompile would be part of the testRuntime as well.

Adding the project(':web-27-config') dependency to both testCompile and testRuntime

dependencies {
    compile project(':web-27-repository-api')
    testCompile project(':web-27-config')
    testRuntime project(':web-27-config')
}

is effectively the same as:

dependencies {
    compile project(':web-27-repository-api')
    testCompile project(':web-27-config')
    //testRuntime project(':web-27-config')
}

You do not need to add it to testRuntime because testRuntime includes testCompile. However, if you add it to testRuntime, it is only available when the tests run. It is not available for the test to compile against because testCompile does not extend testRuntime. It’s the other way around.

You can declare it one line. The one line just needs to add it to the configuration that is extended by other configurations that might need it, not the configuration that extends the other configurations.


(Manuel Jordan) #3

Hello James

Thanks by the reply, very interesting the answer.

I understand in a 100% that anything added to testCompile would be part of the testRuntime as well, it because we know that testRuntime extends/includes from testCompile, but I have assumed that is mandatory always declare testRuntime to let extends all from testCompile. That’s because I thought that

dependencies {
    compile project(':web-27-repository-api')
    //testCompile project(':web-27-config')
    testRuntime project(':web-27-config')
}

Should be valid. I thought that internally automatically testCompile project(':web-27-config') was generated by gradle from testRuntime project(':web-27-config').

Now your code works and is inverse. Now my confusion is:

dependencies {
    compile project(':web-27-repository-api')
    testCompile project(':web-27-config')
    //testRuntime project(':web-27-config')
}

Works, but:

Question 01 how works the testing scenario when testRuntime has not been declared and theoretically it extends from testCompile?

Now, having:

project(':web-27-repository-jdbc') {
	description 'Repository JDBC'
	dependencies {
 	   compile project(':web-27-repository-api')
 	   testCompile project(':web-27-config')
 	   testCompile project(':web-27-config').sourceSets.test.output 	   
 	   //testRuntime project(':web-27-config') 	
 	   //testRuntime project(':web-27-config').sourceSets.test.output 	     
	}
}

How I can declare the testCompile in one line?. Yes both are mandatory, otherwise my testing does not load the .sql files from src/test/resources and all fail.

Thanks in advance.


(James Justinic) #4

The code in the dependencies { ... } block does not declare any configurations. It is only adding dependencies to configurations that have already been created. Applying the java plugin creates all of the configurations that you’ve mentioned, plus some additional ones. See configurations added by the java plugin for the complete list. If you were declaring any configurations, that would be done with the ConfigurationContainer / configurations { ... } block.

If you really want to combine these two, you can use groovy list notation:

testCompile( [ project(':web-27-config'), project(:web-27-config').sourceSets.test.output ] )

That gives you one line, but it’s arguably more difficult to read. If you’re going to do this in several of your projects, you might want to consider creating a helper method instead. I additionally added evaluationDependsOn just in case evaluation ordering might be an issue somewhere.

ext.projectAndTest = { projectName ->
    evaluationDependsOn(projectName)
    [ project(projectName), project(projectName).sourceSets.test.output ]
}

This would add a couple additional, but reusable lines. However, you could then do easy to read one-liners like this:

testCompile projectAndTest(':web-27-config')

(Manuel Jordan) #5

Thanks a lot James!

Your reply had resolved my doubts.

Best Regards!