1. In this tutorial, we will show you how to create two custom annotations – @Test and @TestInfo , to simulate a simple
unit test framework.
P.S This unit test example is inspired by this official Java annotation article.
1. @Test Annotation
This @interface tells Java this is a custom annotation. Later, you can annotate it on method level like
this @Test(enable=false) .
Test.java
packagepackage comcom..mkyongmkyong..testtest..corecore;;
importimport javajava..langlang..annotationannotation..ElementTypeElementType;;
importimport javajava..langlang..annotationannotation..RetentionRetention;;
importimport javajava..langlang..annotationannotation..RetentionPolicyRetentionPolicy;;
importimport javajava..langlang..annotationannotation..TargetTarget;;
@Retention@Retention((RetentionPolicyRetentionPolicy..RUNTIMERUNTIME))
@Target@Target((ElementTypeElementType..METHODMETHOD)) //can use in method only.//can use in method only.
publicpublic @@interfaceinterface TestTest {{
//should ignore this test?//should ignore this test?
publicpublic booleanboolean enabledenabled(()) defaultdefault truetrue;;
}}
Note
Method declarations must not have any parameters or a throws clause. Return types are restricted to primitives,
String, Class, enums, annotations, and arrays of the preceding types.
2. @TesterInfo Annotation
This @TesterInfo is applied on class level, store the tester details. This shows the different use of return types – enum,
array and string.
TesterInfo.java
packagepackage comcom..mkyongmkyong..testtest..corecore;;
importimport javajava..langlang..annotationannotation..ElementTypeElementType;;
importimport javajava..langlang..annotationannotation..RetentionRetention;;
importimport javajava..langlang..annotationannotation..RetentionPolicyRetentionPolicy;;
importimport javajava..langlang..annotationannotation..TargetTarget;;
@Retention@Retention((RetentionPolicyRetentionPolicy..RUNTIMERUNTIME))
@Target@Target((ElementTypeElementType..TYPETYPE)) //on class level//on class level
publicpublic @@interfaceinterface TesterInfoTesterInfo {{
2. publicpublic enumenum PriorityPriority {{
LOWLOW,, MEDIUMMEDIUM,, HIGHHIGH
}}
PriorityPriority prioritypriority(()) defaultdefault PriorityPriority..MEDIUMMEDIUM;;
StringString[[]] tagstags(()) defaultdefault """";;
StringString createdBycreatedBy(()) defaultdefault "Mkyong""Mkyong";;
StringString lastModifiedlastModified(()) defaultdefault "03/01/2014""03/01/2014";;
}}
3. Unit Test Example
Create a simple unit test example, and annotated with the new custom annotations – @Test and @TesterInfo .
TestExample.java
packagepackage comcom..mkyongmkyong..testtest;;
importimport comcom..mkyongmkyong..testtest..corecore..TestTest;;
importimport comcom..mkyongmkyong..testtest..corecore..TesterInfoTesterInfo;;
importimport comcom..mkyongmkyong..testtest..corecore..TesterInfoTesterInfo..PriorityPriority;;
@TesterInfo@TesterInfo((
prioritypriority == PriorityPriority..HIGHHIGH,,
createdBycreatedBy == "mkyong.com""mkyong.com",,
tagstags == {{"sales""sales",,"test""test" }}
))
publicpublic classclass TestExampleTestExample {{
@Test@Test
voidvoid testAtestA(()) {{
ifif ((truetrue))
throwthrow newnew RuntimeExceptionRuntimeException(("This test always failed""This test always failed"));;
}}
@Test@Test((enabledenabled == falsefalse))
voidvoid testBtestB(()) {{
ifif ((falsefalse))
throwthrow newnew RuntimeExceptionRuntimeException(("This test always passed""This test always passed"));;
}}
@Test@Test((enabledenabled == truetrue))
voidvoid testCtestC(()) {{
ifif ((1010 >> 11)) {{
// do nothing, this test always passed.// do nothing, this test always passed.
}}
}}
}}
4. Java reflection – Read the Annotation
Below example show you how to use Java reflection APIs to read and process the custom annotations.
RunTest.java
packagepackage comcom..mkyongmkyong..testtest;;
3. p g y g ;
importimport javajava..langlang..annotationannotation..AnnotationAnnotation;;
importimport javajava..langlang..reflectreflect..MethodMethod;;
importimport comcom..mkyongmkyong..testtest..corecore..TestTest;;
importimport comcom..mkyongmkyong..testtest..corecore..TesterInfoTesterInfo;;
publicpublic classclass RunTestRunTest {{
publicpublic staticstatic voidvoid mainmain((StringString[[]] argsargs)) throwsthrows ExceptionException {{
SystemSystem..outout..printlnprintln(("Testing...""Testing..."));;
intint passedpassed == 00,, failedfailed == 00,, countcount == 00,, ignoreignore == 00;;
ClassClass<<TestExampleTestExample>> objobj == TestExampleTestExample..classclass;;
// Process @TesterInfo// Process @TesterInfo
ifif ((objobj..isAnnotationPresentisAnnotationPresent((TesterInfoTesterInfo..classclass)))) {{
Annotation annotationAnnotation annotation == objobj..getAnnotationgetAnnotation((TesterInfoTesterInfo..classclass));;
TesterInfo testerInfoTesterInfo testerInfo == ((TesterInfoTesterInfo)) annotationannotation;;
SystemSystem..outout..printfprintf(("%nPriority :%s""%nPriority :%s",, testerInfotesterInfo..prioritypriority(())));;
SystemSystem..outout..printfprintf(("%nCreatedBy :%s""%nCreatedBy :%s",, testerInfotesterInfo..createdBycreatedBy(())));;
SystemSystem..outout..printfprintf(("%nTags :""%nTags :"));;
intint tagLengthtagLength == testerInfotesterInfo..tagstags(())..lengthlength;;
forfor ((String tagString tag :: testerInfotesterInfo..tagstags(()))) {{
ifif ((tagLengthtagLength >> 11)) {{
SystemSystem..outout..printprint((tagtag ++ ", "", "));;
}} elseelse {{
SystemSystem..outout..printprint((tagtag));;
}}
tagLengthtagLength----;;
}}
SystemSystem..outout..printfprintf(("%nLastModified :%s%n%n""%nLastModified :%s%n%n",, testerInfotesterInfo..lastModifiedlastModified(())));;
}}
// Process @Test// Process @Test
forfor ((Method methodMethod method :: objobj..getDeclaredMethodsgetDeclaredMethods(()))) {{
// if method is annotated with @Test// if method is annotated with @Test
ifif ((methodmethod..isAnnotationPresentisAnnotationPresent((TestTest..classclass)))) {{
Annotation annotationAnnotation annotation == methodmethod..getAnnotationgetAnnotation((TestTest..classclass));;
Test testTest test == ((TestTest)) annotationannotation;;
// if enabled = true (default)// if enabled = true (default)
ifif ((testtest..enabledenabled(()))) {{
trytry {{
methodmethod..invokeinvoke((objobj..newInstancenewInstance(())));;
SystemSystem..outout..printfprintf(("%s - Test '%s' - passed %n""%s - Test '%s' - passed %n",, ++++countcount,, methodmethod..getNamegetName(())));;
passedpassed++++;;
}} catchcatch ((ThrowableThrowable exex)) {{
SystemSystem..outout..printfprintf(("%s - Test '%s' - failed: %s %n""%s - Test '%s' - failed: %s %n",, ++++countcount,, methodmethod..getNamegetName(()),, exex..getCausegetCause(())));;
failedfailed++++;;
}}
}} elseelse {{
SystemSystem..outout..printfprintf(("%s - Test '%s' - ignored%n""%s - Test '%s' - ignored%n",, ++++countcount,, methodmethod..getNamegetName(())));;
ignoreignore++++;;
}}