Running Groovy test cases with JUnit 5 - groovy

Maybe this is very simple, but I couldn't find any examples on the web:
I'd like to use JUnit 5 to run a unit test implemented as a Groovy class. My current setup seems to launch JUnit 5, but fail to detect the test case. IntelliJ recognizes the test, but fails to run it. If I add a Java unit test, it is launched correctly.
Here's what I have now:
Project structure
src
main
groovy
# production code
test
groovy
UnitTest.groovy
build.gradle
...
build.gradle
plugins {
id 'groovy'
}
dependencies {
compile localGroovy()
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.1.1'
}
test {
useJUnitPlatform()
}
UnitTest.groovy
import org.junit.jupiter.api.Test
class UnitTest {
#Test
def shouldDoStuff() {
throw new RuntimeException()
}
}
I'm using Gradle 4.10.
Any ideas?

JUnit requires all testing method to use return type void. Groovy's def keyword is compiled to an Object type, so your method compiles to something like this in Java:
import org.junit.jupiter.api.Test
public class UnitTest {
#Test
Object shouldDoStuff() {
throw new RuntimeException();
}
}
If you try this out as a Java test, it won't find the test case neither. The solution is very simple - replace def with void and your Groovy
test case will be executed correctly.
src/test/groovy/UnitTest.groovy
import org.junit.jupiter.api.Test
class UnitTest {
#Test
void shouldDoStuff() {
throw new RuntimeException()
}
}
Demo:

Related

groovy is not finding annotated tests

Still new to Groovy and trying to figure out unit testing. I'm trying to use the Junit4 style of testing.
import org.junit.Test
import junit.framework.*
import junit.textui.TestRunner
class DegenerateTestCase {
#Test
void testAlwaysTrue() {
assert true
}
#Test
void someMethodName() {
assert true
}
}
TestRunner.run(DegenerateTestCase)
But when I run the script, I get
There was 1 failure:
warning(junit.framework.TestSuite$1)junit.framework.AssertionFailedError:> No tests found in DegenerateTestCase
This has to be something simple that I'm missing.
I am using Eclipse Java EE IDE for Web Developers, Oxygen.3a Release (4.7.3a). I have the Groovy plugin downloaded from the marketplace (compiler level 2.5).
I tried running it with junit5 which had only one difference which was instead of having import org.junit.Test I had import static org.junit.jupiter.api.Assertions.*. I didnt need import junit.framework.* or import junit.textui.TestRunner I just ran it as is and worked fine.
I then switched to Junit4 and did the same but switched import static org.junit.jupiter.api.Assertions.* to import org.junit.Test and it works.
my code looks like this:
import org.junit.Test
class DegenerateTestCase {
#Test
void testAlwaysTrue() {
assert true
}
#Test
void someMethodName() {
assert true
}
}

How to use Dagger for Groovy?

How to configure dagger to inject groovy classes, and to inject into groovy classes?
I was initially trying to get dagger to inject a groovy class into my java app, and I found dagger was complaining the groovy class is not found. Looking at the log, it seems that compileGroovy happens after compileJava. And the annotation processing of dagger compiler seems to be in compileJava. I guessed that might be the problem -- no groovy classes are available at this time. But I've yet figured out a way to coerce either of dagger or groovy to work with the other.
It seems I could not upload a .tar.gz. But if anyone needs a minimal demo code for what I meant to achieve, these might help (with gradle 7):
build.gradle:
plugins {
id 'groovy'
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
annotationProcessor 'com.google.dagger:dagger-compiler:2.+'
implementation 'com.google.dagger:dagger:2.+'
implementation 'org.codehaus.groovy:groovy-all:3.+'
}
settings.gradle:
rootProject.name = 'groovy-dagger1'
src/main/groovy/org/example/dagger/MainComponent.groovy:
package org.example.dagger
import dagger.Component
#Component(modules = [
MainModule,
])
interface MainComponent {
String message();
}
src/main/groovy/org/example/dagger/MainModule.groovy:
package org.example.dagger
import dagger.Module
import dagger.Provides
#Module
final class MainModule {
#Provides
static String message() {
return 'Hello Groovy Dagger!'
}
}
src/main/groovy/org/example/main/Main.groovy:
package org.example.main;
class Main {
static void main(String[] args) {
// Dagger component does not exist :/
// println DaggerMainComponent.create().message()
}
}
By default, the groovy compiler will not run the java annotation processors...
You can add this to your build.gradle:
compileGroovy {
groovyOptions.javaAnnotationProcessing = true
}
You will of course need to add an import
import org.example.dagger.DaggerMainComponent
To Main.groovy

Mockito 2 and junit 5 : mocking classes

I have a strange behaviour with mockito 2 and Junit 5 : Mockito can't mock a class.
I extracted my test to a simple test case :
#ExtendWith(MockitoJavaExtension.class)
class JavaTest {
#Test
void shouldMockClass(){
final MockedJavaClass mock = mock(MockedJavaClass.class);
when(mock.execute()).thenReturn(Collections.singletonList("some value"));
assertEquals(1, mock.execute().size());
}
#Test
void shouldMockInterface(){
final MockedJavaInterface mock = mock(MockedJavaInterface.class);
when(mock.execute()).thenReturn(Collections.singletonList("some value"));
assertEquals(1, mock.execute().size());
}
}
class MockedJavaClass{
List<String> execute(){
throw new IllegalArgumentException();
}
}
interface MockedJavaInterface{
default List<String> execute(){
throw new IllegalArgumentException();
}
}
When I run this test, I get the IllegalArgumentException :
JUnit Jupiter:JavaTest:shouldMockClass()
MethodSource [className = 'JavaTest', methodName = 'shouldMockClass', methodParameterTypes = '']
=> java.lang.IllegalArgumentException
MockedJavaClass.execute(JavaTest.java:36)
JavaTest.shouldMockClass(JavaTest.java:19)
It means that the class is not mocked at all.
I also tried with an external class (not an inner one), and the issue is still the same...
This is also my build.gradle :
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.junit.platform:junit-platform-gradle-plugin:1.1.1"
}
}
apply plugin: 'idea'
apply plugin: 'java'
apply plugin: 'org.junit.platform.gradle.plugin'
sourceCompatibility = 8
targetCompatibility = 8
repositories {
mavenCentral()
}
dependencies {
testCompile "org.mockito:mockito-core:2.18.0"
testCompile "org.mockito:mockito-junit-jupiter:2.18.0"
testCompile("org.junit.jupiter:junit-jupiter-api:5.1.1")
testCompile("org.junit.jupiter:junit-jupiter-params:5.1.1")
testRuntime("org.junit.jupiter:junit-jupiter-engine:5.1.1")
testRuntime("org.junit.platform:junit-platform-launcher:1.1.1")
}
junitPlatform {
filters {
engines {
include 'junit-jupiter'
}
includeClassNamePattern '.*Test'
}
}
I also tried with the mockito junit5 extension to inject mocks, but I still have the problem...
Any help will be appreciated !
I finally ended finding the solution : My first test was a Kotlin one, in a "open class" but a non-opened method declaration.
Mockito can't mock a method with a package access nor a final method !
In this particular case, it just calls the real method when you try to mock it, without telling you anything...
Maybe this post will be useful for someone ! –
You didn't mock the execute function on your MockClass so it used the implementation of execute that was in the class definition - in other words the IllegalArgumentException.
You need to setup your mocks such that they provide dummy implementations of the methods that are going to be required as dependancies to your test case. In this particular case it doesn't appear you are testing anything really, just learning Mockito?
So yea, the answer is - provide mock implementations or the default will be used.

How to properly quit WebDriver after completing all UI tests with Cucumber

We are using Selenium WebDriver to do UI testing, along with Cucumber. The language is Groovy, and the build tool is Gradle. Because it is expensive to create a WebDriver instance, we want to instantiate only one WebDriver instance and use it through all tests. However, we are having trouble to quit the driver properly after all tests are completed. Namely, the browser process spawned during the tests is still alive after running all the tests.
The code is currently structured like below.
// Test base class
class UITestBase {
WebDriver driver
static {
init()
}
static void init() {
// instantiate a webdriver
}
}
// Entry class of cucumber run
RunWith( Cucumber )
Cucumber.Options(...)
class CukeRunEntry {}
// Cucumber step class
class WhenSteps extends UITestBase {
#When(/^something happens$/)
void something_happens() {
// step implmentation
}
}
So, how can I call driver.quit() after all tests are finished but before gradle finishes the test task (we run the tests with ./gradlew test from command line)? I tried overriding the finalize() method, but that didn't help.
Thank you very much.
If I were you, I would prefer using SharedDriver that you can find here => https://github.com/cucumber/cucumber-jvm/blob/master/examples/java-webbit-websockets-selenium/src/test/java/cucumber/examples/java/websockets/SharedDriver.java
It makes life easier.
Edit
If you don't wish to use SharedDriver, you can add a block like below to the UITestBase class as illustrated in the question:
private static final Thread CLOSE_THREAD = new Thread() {
#Override
public void run() {
try {
driver.quit()
} catch ( Exception e ) {
}
}
}
static {
init()
Runtime.getRuntime().addShutdownHook(CLOSE_THREAD)
}
The above code is essentially what's used in SharedDriver to ensure safe close of the WebDriver instance.

Unit tests - run task programmatically

I'm creating custom task for gradle. I don't know how I can create task which will use my custom task class. Is it possible? I want to create this task for functional tests which will be runned on jenkins.
This is my custom task:
package pl.gradle
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class MyCustomTask extends DefaultTask {
public MyCustomTask() {
// do something
}
#TaskAction
def build() {
ant.echo(message: "only for tests")
}
}
And this is my test class:
package pl.gradle
import static org.junit.Assert.*
import org.gradle.testfixtures.ProjectBuilder
import org.gradle.api.Project
import org.junit.Before;
import org.junit.Test
class MyCustomTaskTest {
private Project project;
def task
#Before
public void setUp() {
project = ProjectBuilder.builder().build()
task = project.task("build", type: MyCustomTask)
}
#Test
public void taskCreatedProperly() {
assertTrue(task instanceof MyCustomTask)
}
#Test
public void shouldRunTask() {
// task.execute() // how to run this task? I want to run build() method from MyCustomTask class which is #TaskAction
}
}
ProjectBuilder is meant for lower-level tests that don't execute tasks. Its sweet spot is testing plugins. In addition you'd write higher-level tests that execute real builds (and therefore also tasks). You'd typically use the Gradle tooling API to kick off these builds. Check out the tooling API samples in the full Gradle distribution.
Call Action.execute yourself for each of the task actions:
project.tasks.getByName("myTask").with { Task task ->
assertEquals task.group, 'My Group'
task.actions.each { Action action ->
action.execute task
}
}
I've previously mentioned this here: https://stackoverflow.com/a/63613564/410939

Resources