There are some modules that contain methods which are marked with the following annotation:
#SuppressWarnings({"WeakerAccess"})
When this annotation is added,
the compiler does not give warning about the access modifier can be more private.
Some of the time this is done because some child class (outside the module) will override the method.
When this is the case,
we are required to add a comment stating that the method be overridden.
Now,
for every method and variable,
we have two things,
the annotation and the comment.
Does Java let us create an annotation which can indicate both cases.
This is what I have:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
#Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
#Retention(RetentionPolicy.SOURCE)
#SuppressWarnings({"WeakerAccess"})
public #interface WillBeOverriden { } // Ignore the ugly name
The goal of this new annotation is that it will behave exactly the same as the SuppressWarnings annotation and removes the need to add a java comment; since the annotation will act as the comment.
This stackoverflow question seems to have the answer,
but my compiler still complains that the field can be more private.
Related
(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
}
Because of problems with Powermock and Java 11, we have had to use the #PowerMockIgnore on all our test classes.
#PowerMockIgnore({ "javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*",
"org.xml.*", "org.w3c.dom.*", "com.sun.org.apache.xalan.*", "javax.activation.*" })
In order to avoid duplicating this in all test classes, we created a custom annotation to be used instead that had this PowerMockIgnore defined on one place.
So that all we would need in all our test classes would be
#SuppressPowerMockInitError
However: This custom annotation does not seem to work.
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
#Retention(RUNTIME)
#Target({ TYPE, METHOD })
#Inherited
#Documented
#PowerMockIgnore({ "javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*",
"org.xml.*", "org.w3c.dom.*", "com.sun.org.apache.xalan.*", "javax.activation.*" })
public #interface SuppressPowerMockInitError {
}
It does not look like it is possible to achieve this with annotations.
However creating an abstract class that has this common annotation seems like the best way to achieve this.
import org.powermock.core.classloader.annotations.PowerMockIgnore;
#PowerMockIgnore({ "javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*",
"org.xml.*", "org.w3c.dom.*", "com.sun.org.apache.xalan.*", "javax.activation.*" })
public abstract class AbstractPowerMockTest {
}
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/
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.
This seems like it shouldn't compile and run as Object does not have a fail() method. At compile time is something funky happening? (I am using NetBeans):
import static org.junit.Assert.*;
import org.junit.Test;
public class Test {
#Test
public void hello() {
fail();
}
}
Regards,
Guido
Your import static line imports all static members of the Assert class into the static namespace of your compilation unit. The fail() call refers to Assert.fail().
The confusion you are experiencing regarding where fail() is defined is precisely why I don't usually recommend using import static. In my own code, I usually import the class and use it to invoke the static methods:
import org.junit.Assert;
import org.junit.Test;
public class Test {
#Test
public void hello() {
Assert.fail();
}
}
Much more readable.
However, as JB Nizet points out, it is fairly common practice to use import static for JUnit's assertions; when you write and read enough JUnit tests, knowing where the assertion methods come from will become second nature.
This is perfectly correct and it will run and compile - I already checked using eclipse.
The reason is the static import:
import static org.junit.Assert.*;
that adds all the static fields or methods from the org.junit.Assert class - hence including fail() method.
Nevertheless a problem that might occur is the fact that the name of your test class is the same as the name of the annotation
#Test
hence it will generate an error:
The import org.junit.Test conflicts with a type defined in the same file
This error is coming because your classname and annotation name are same(Test).Change your class name to 'Test1' or other than Test.