IntelliJ run context for JUnit TestTemplates - java

In JUnit 5 you can define your own test template and bind it to an annotation.
Instead of #Test or #ParameterizedTest now I can use my own test annotaion #MyTest(...)
The problem is that Intellij does not recognize this annotation as JUnit test annotation thus does not give me the option to run/debug this test.
Can I extend this list of annotations that tells IntelliJ this is a test?
Picture on the left is a standard test where the context shows a run function.
Picture on the right shows my template which works perfectly just the context does not recognize it as a test.
My test template looks like this:
#Target(
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.FUNCTION
)
#Retention(AnnotationRetention.RUNTIME)
#Execution(ExecutionMode.CONCURRENT)
#TestTemplate
#ExtendWith(ScTestExtension::class)
annotation class ScTest(
// ... some properties
)
class ScTestExtension : TestTemplateInvocationContextProvider {
override fun supportsTestTemplate(context: ExtensionContext): Boolean {
return true
}
override fun provideTestTemplateInvocationContexts(extensionContext: ExtensionContext): Stream<TestTemplateInvocationContext> {
// ... return invocation context
}
}

Your ScTest.java should look similar to this one:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Test;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Test
public #interface ScTest {}
Derived from https://junit.org/junit5/docs/current/user-guide/#writing-tests-meta-annotations
IIRC, IDEA and other IDEs look for an instance of Testable to display the "Run..." icon. But normally, you shouldn't use that annotation directly. It should suffice to have it meta-annotated with #Test, #TestTemplate, or friends.
Here's another example using #TestTemplate that worked (at least, two years ago): CartesianProductTest.java
#TestTemplate
#ExtendWith(CartesianProductProvider.class)
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface CartesianProductTest {...}
Here is how "IntelliJ IDEA 2019.3 EAP (Community Edition) Build #IC-193.4386.10, built on October 9, 2019" shows the usage of the #CartesianProductTest annotation today:
Perhaps you need to switch to dark mode...

Related

junit 5 custom parametrized tests

I'm using Junit 5 parametrized tests with custom name as follow
#ParameterizedTest(name = PARAMETERIZED_TESTS_NAME_PLACEHOLDER)
where PARAMETERIZED_TESTS_NAME_PLACEHOLDER is defined in its own utility class
public static final String PARAMETERIZED_TESTS_NAME_PLACEHOLDER = "#{index} [{argumentsWithNames}]";
the problem I'm facing is that as I'm using extensively the parametrized tests, my code is cluttered by these #ParameterizedTest(name = PARAMETERIZED_TESTS_NAME_PLACEHOLDER).
so I created a custom annotation to fix this
import java.lang.annotation.*;
import org.junit.jupiter.params.*;
#ParameterizedTest(name = PARAMETERIZED_TESTS_NAME_PLACEHOLDER)
#Inherited
public #interface CustomParametrizedTest {
}
but this annotation is ignored when I use it in the test cases
any help would be appreciated
The #ParamterizedTest annotation appears to have a retention policy of runtime suggesting it's needed and processed at runtime. Try this config
#ParameterizedTest(name = PARAMETERIZED_TESTS_NAME_PLACEHOLDER)
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface CustomParametrizedTest {
}
It seems odd to me that this is not the default retention policy for custom annotations, see more from this post.

How to combine JUnit annotations into a custom annotation?

(Using OpenJDK-13 and JUnit5-Jupiter)
The problem is that my unit tests each make use of a not-small JUnit annotation system, something like this:
#ParameterizedTest
#MethodSource("myorg.ccrtest.testlogic.DataProviders#standardDataProvider")
#Tags({#Tag("ccr"), #Tag("standard")})
This makes test authoring a little tedious, test code a little long and of course, when a change is needed, it's a chore!
Was wondering if I could create my own JUnit annotation: #CcrStandardTest, which would imply all of the annotations above?
I also tried shifting the annotations up in the class definition (hoping they would then apply to all methods of the class), but the compiler says no: "#ParameterizedTest is not applicable to type"
You can make a composed annotation:
JUnit Jupiter annotations can be used as meta-annotations. That means that you can define your own composed annotation that will automatically inherit the semantics of its meta-annotations.
For example:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
#ParameterizedTest
#MethodSource("myorg.ccrtest.testlogic.DataProviders#standardDataProvider")
#Tag("ccr")
#Tag("standard")
public #interface CcrStandardTest {}
You would then place the composed annotation on your test method:
#CcrStandardTest
void testFoo(/* necessary parameters */) {
// perform test
}

Run methods annotated with #Category from IntelliJ IDEA

I have a test class with multiple test methods that I would like to group by some criteria. For this purpose, using JUnit's #Category annotation on a method level seemed like a fine solution:
public class TestClass {
#Test
#Category(AssignmentServiceCategory.class)
public void testMethod1() {}
#Test
#Category(OtherCategory.class)
public void testMethod2() {}
}
I would like to create different run configurations in IntelliJ IDEA for those separate categories so that only the test methods annotated with certain category are executed. My configuration looks like this:
However, when I run this, all of the tests from the class where the method is declared are run, instead of only the ones annotated with specified category. Is my configuration incorrect, or does IDEA allow only class-level #Category annotations?
Versions:
IntelliJ IDEA 2018.1 (181.4203.550)
JRE: 1.8.0_152-release-1136-b20 amd64
JUnit 4.12
UPDATED
I tried to reproduce the issue and could not.
Here's my Test Class
package com.mytests.category;
import org.junit.Test;
import org.junit.experimental.categories.Category;
public class MyTest {
#Test
#Category(PerformanceTests.class)
public void testMethod1() {
System.out.println("method1");
}
#Test
#Category(RegressionTests.class)
public void testMethod2() {
System.out.println("method2");
}
}
Make sure you have the necessary interfaces. In JUnit, you need to create marker interfaces to represent the categories:
package com.mytests.category;
public interface RegressionTests {}
and
package com.mytests.category;
public interface PerformanceTests {}
Then in IntelliJ, I ran the tests once and it creates a configuration for me automatically. Then I edit the configuration
The results were as expected:
Only testMethod1 was executed.
OLDER ANSWER
Or from IntelliJ's Doc (https://www.jetbrains.com/help/idea/run-debug-configuration-junit.html)
Category Select this option if you only want to run test classes and
test methods that are annotated either with the category given with
the #IncludeCategory annotation, or a subtype of this category. Fill in the following fields:
Category Specify the desired category. Type category name, or click
browseButton and select the desired category in the dialog that opens.
Or You could create a TestSuite and specify (in there) which categories the suite is to include.
Something like
package org.mytests.category;
import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
#RunWith(Categories.class)
#Categories.IncludeCategory(RegressionTests.class)
#Suite.SuiteClasses({ClassA.class, ClassB.class, ClassC.class})
public class RegressionTestSuite {
}
I have (had) the same problem with Intellij 2020.1.2
There seems to be a bug related to what setting you select for search for tests.
If i choose in single module all the test are executed, even the ones annotated with other Categories.
If I choose any of the other options (in whole project, across module dependencies) it simply works as expected..

Junit & Allure Reporting 2 - How can we programmatically set Issue and TmsLink?

the standard use of these works great, #TmsLink("foo") #Issue("bar) However when using a dataProvider scenario, how can I programmatically set these values on each iteration of the #Test method?
Each csv entry for my test data will contain both an Id for TmsLink and Issue, how can I make each test set its own for good reporting purposes? We can do it with SeverityLevel which looks like a simple enum, however Issue/TmsLink are interfaces with #Target at Method/Type only
SeverityLevel severity = severityLevel.CRITICAL;
package io.qameta.allure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to link tests with issues.
*/
#Documented
#Inherited
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
#Repeatable(Issues.class)
public #interface Issue {
String value();
}
Thank you.
to anyone coming along to this at a later stage, I figured it out by overriding the annotation values at runtime, its not amazing by any stretch but it works, I wrote up a blog post on the subject:
https://symonk.github.io/2017-10-26-overriding-allure-reporting-annotational-values-at-runtime-for-issue-tmslink-displayname/

what use of userdefined annotation witout any method?

In this code we have one user defined Annotation but without body any method what could be use of this
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.SOURCE)
#Target( { ElementType.TYPE })
public #interface InputBean {
}
The #Retention(RetentionPolicy.SOURCE) tells us that whatever use it has, it's only at the source code level -- the annotation is forgotten by the time the compiler is done, and isn't in the generated class files.
That leaves two options:
as a visual clue (ie, documentation) to human coders
to be used by an annotation processor
Without knowing more, we can't tell which of those is the case here.

Categories

Resources