Separating integration vs. unit tests in gradle based on abstract class - gradle

I'm trying to separate my gradle/spock tests into two groups:
unit tests
integration tests
My attempt was with jUnit's #Category. In build.gradle I created task for integration/e2e tests:
task e2eTest(type: Test) {
useJUnit {
includeCategories 'com.foo.bar.baz.E2ESpec'
}
}
And marked my base abstract class with #Category(E2ESpec), but it doesn't work.
I've noticed that inheritance works, but only with single level inheritance:
#Category(E2ESpec)
abstract class AbstractSpec {...}
class ActualSpec extends AbstractSpec {...}
but doesn't work for cases like:
#Category(E2ESpec)
abstract class AbstractSpect {...}
abstract class AnotherAbstractSpec extends AbstractSpec {...}
class ActualSpec extends AnotherAbstractSpec {...}
Any idea how to fix it?
PS. I've many classes extending AbstractSpec and new classes appears, so I don't want #Category on each spec. Maybe pure gradle solution exists?

Create a new sourceset for integration tests, with a corresponding task. See How do I add a new sourceset to Gradle?

Related

Using getProject() with Gradle Configuration Cache

Gradle documentation states that using the getProject() method in the #TaskAction method of a Task class should not be used if you want compatibility with Gradle Configuration Cache. The question I have is that, suppose you have something like this:
public abstract class AbstractMyTask extends DefaultTask {
#Internal
protected abstract DirectoryProperty getRootDirectory();
protected AbstractMyTask() {
getRootDirectory().convention(getProject().getRootProject().getLayout().getProjectDirectory());
}
}
The general intent of the code snippet is to have a Directory property representing the root project directory (ie. a safe replacement for getProject().getRootDir()), and it seems like the getProject() call in the constructor would be okay. I'd like some sober second thought on whether that is the case.

Private method visibility confusion

I am confused with Groovy method visibility in the context of my Gradle build.
For some tests in my project, I have to first start a server.
For this I created a custom task class that extends Gradle's Test like so:
class TestWithServer extends Test {
TestWithServer() {
super()
beforeTest {
startServer()
}
}
private void startServer() {
println('placeholder')
}
}
But if I try to run such a task, I get an error:
Could not find method startServer() for arguments [] on task ':testWithServer' of type TestWithServer.
I found that when I change the visibility of startServer() to the default (public), the task runs fine.
How come I can't use the private method from within its own class?
It is not the same class, because Gradle adds some magic to the task types. Just add println this.class into the beforeTest closure to see the name of the actual class (something like TestWithServer_Decorated). This additional magic also explains why the error message contains the task name and how the class knows about being a task (type) at all. Since the decorated class is a subclass of your class you can use the protected modifier to encapsulate your method.

Use #Timed for inheritanced functions

We use a abstract classes for services like this pseudocode
abstract class AbstractApiService {
#Timed(value="get", useClassPrefix=true)
def get(Long id) {
... returns sth ....
}
#Timed(value="create", useClassPrefix=true)
def create(Map params) {
... returns sth ....
}
}
There are beans which inherit AbstractApiService and serve features like creating, deleting, updating entities like
class UserAccountService extends AbstractApiService {
... code ....
}
I would like to get metrics for each call a function from child classes like UserAccountService, but Prometheus sends events with full parent class prefix.
App is based on Grails 3.3.8
build.gradle:
compile 'com.moelholm:prometheus-spring-boot-starter:1.0.2'
compile 'io.dropwizard.metrics:metrics-core:4.0.0-alpha2'
compile 'io.dropwizard.metrics:metrics-jvm:4.0.0-alpha2'
compile 'org.grails.plugins:dropwizard-metrics:1.0.0.M2'
Unfortunately, I believe you will have to define the #Timed annotation for each method you want tracked. I don't think that the annotation code will spin up a separate metric for each concrete class.
I created a custom manual solution
https://gist.github.com/michmzr/1e03534bc5fb6df89065f6964acf9c71

Spring profiles on integration tests class

we have selenium tests which are ran by java test class.
On local environment everything is ok, but I want to switch off those tests when run on jenkins.
So I use:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebIntegrationTest("server.port=1234")
#Profile("!jenkins")
#ActiveProfiles("integrationtests")
public class LoginAndEditProfileSeleniumTest {
...
What works:
running mvn clean test run all tests locally, with integrationtests profile active. I dont want to pass any additional parameter.
What I want to achieve:
running mvn clean test -Dspring.profiles.active=jenkins switch off this test.
Can I merge somehow profile passed by parameter, ActiveProfile annotation and take Profile annotation into consideration? :)
//update:
Its possible to use class extending ActiveProfilesResolver:
public class ActiveProfileResolver implements ActiveProfilesResolver {
#Override
public String[] resolve(Class<?> testClass) {
final String profileFromConsole = System.getProperty("spring.profiles.active");
List<String> activeProfiles = new ArrayList<>();
activeProfiles.add("integrationtests");
if("jenkins".contains(profileFromConsole)){
activeProfiles.add("jenkins");
}
return activeProfiles.toArray(new String[activeProfiles.size()]);
}
}
but it seems to not to cooperate with #Profile anyway ( jenkins profile is active but test is still running ) .
#Profile has zero affect on test classes. Thus, you should simply remove that annotation.
If you want to enable a test class only if a given system property is present with a specific value, you could use #IfProfileValue.
However, in your scenario, you want to disable a test class if a given system property is present with a specific value (i.e., if spring.profiles.active contains jenkins).
Instead of implementing a custom ActiveProfileResolver, a more elegant solution would be to use a JUnit assumption to cause the entire test class to be ignored if the assumption fails.
This should work nicely for you:
import static org.junit.Assume.*;
// ...
#BeforeClass
public static void disableTestsOnCiServer() {
String profilesFromConsole = System.getProperty("spring.profiles.active", "");
assumeFalse(profilesFromConsole.contains("jenkins"));
}
Regards,
Sam (author of the Spring TestContext Framework)

Spring #ContextHierarchy in a multilevel test class hierarchy (using Scala and ScalaTest)

Instead of having several full blown applications contexts, copy&pasting 99% of the content and adding/removing only a few lines where the context should differ, I'd rather have all the generic stuff in one parent context i.e. "rootContext.xml". Everything else would be part of the child context and either be merged into the parent context or replace it.
[1] describes all you need to set up a #ContextHierarchy and use a unit test class hierarchy. But it isn't working.
My class hierarchy first:
#RunWith(classOf[JUnitRunner])
#ContextHierarchy(value = Array(new ContextConfiguration(locations = Array("classpath:/rootTestContext.xml"), name = "root")))
class TestBase extends FunSuite {...}
#ContextHierarchy(value = Array(new ContextConfiguration(locations = Array("classpath:/persistenceTestContext.xml"), name = "root", ???inheritLocations = false???)))
class PersistenceTestBase extends TestBase {...}
class BasicTest extends TestBase {
test("blah") { ... }
}
class NeedsExtraContextForPersistenceTest extends PersistenceTestBase {
test("persist!") { ... }
}
Spring application context files:
rootTestContext.xml:
<import resource="classpath:/configfiles/spring/genericCaching.xml"/>
<context:annotation-config/>
<context:component-scan base-package="my.package.cm" />
<context:component-scan base-package="my.package.package2.cm" />
persistenceTestContext.xml:
<import resource="classpath:/configfiles/spring/persistence.xml"/>
So persistenceTestContext.xml should add one line to the parentContext. The generic stuff that used to be there is now in rootTestContect.xml. However when running NeedsExtraContextForPersistenceTest spring's component scanner isn't picking up spring beans for autowiring. It seems as if the scanner as defined in the parent context has no effect. Just to make this clear, there is no issue running the test when using the standard way (via #ContextConfiguration) and a complete persistenceTestContext.xml (that includes the scanner config)
Since there are only a few examples using test hierarchies with #ContextHierarchy and none using Scala + ScalaTest I'd be glad if you could provide some insight.
[1] http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#testcontext-ctx-management-ctx-hierarchies
Those annotations are processed by the Spring JUnit runner, #RunWith(SpringJUnit4ClassRunner.class); if you write standard junit tests (in scala) and use that runner then it should work. If you want to use scalatest with this spring stuff you'll perhaps need to perhaps write your own runner that invokes both the things the spring runner would do and the things that the scalatest runner would do.

Resources