Hello Everyone, I'd like to print out additional test cases descriptive info into any final Junit report, for this I started patching "XMLJUnitResultFormatter" to accept a custom annotation associated to tested method
So now to parameterize well the annotation introspection, I need some information on how retrieving build.xml params values strictly following and according to ant-junit library design, but unfortunately I don't know where to start to find a clear example of. Basically I need something to get current params of the running target. In "XMLJUnitResultFormatter" I implemented the generation of a nested child tag set into tag of the JUnit xml raw data report. But these tags are brutally wired by an "user space" annotation class. The following shows wired tag into testcase tag: [...] This tag set is added only if testcase contains a specific annotation which contains the following attributes: public String title() default "Default test title"; public String desc() default "Default test description"; public String[] input() default {}; Now I would like to pass both name and attributes of the annotation directly from the JUnit target or a nested one, but I don't know how to do it. A more readable code sample usage of all classes that I implemented are available http://www.nabble.com/Regarding-%22Annotated-descriptions%22-of-new-improvements-in-version-4.4-td15348555.html here and presents a wired solution. However here I put (my painful written code, sorry for my awful style %-| ) what I modified to accomplish this. All text formatting follows my unconventional style, and I hope it will be readable even if Nabble try to explode in one line:wistle: ): Here I attached my actual code with all modified/patched Ant sources: http://www.nabble.com/file/p15391637/XMLConstants.java XMLConstants.java http://www.nabble.com/file/p15391637/XMLJUnitResultFormatter.java XMLJUnitResultFormatter.java http://www.nabble.com/file/p15391637/JUnitVersionHelper.java JUnitVersionHelper.java http://www.nabble.com/file/p15391637/junit-frames.xsl A customized stylesheet used by ANT JUnit to produce the final testcase report ("testcase.test.header" & "testcase" template lightly modified with appended additions) http://www.nabble.com/file/p15391637/TestInfo.java Custom descriptive annotation http://www.nabble.com/file/p15391637/EnumTestType.java An optional Enum used by custom annotation just to complicat more :p :-D http://www.nabble.com/file/p15391637/SampleTest.java Testcase sample using custom annotation http://www.nabble.com/file/t906682/6_TestBigRationalFraction.html JUnit descriptive report sample // ===org.apache.tools.ant.taskdefs.optional.junit.XMLConstants=== // // Some consts referring to additional tag set // +++ [...] /** * info element for testcase element * @author rigel alias zetatau * TODO: */ String TESTINFO = "info"; /** * title element for info element * @author rigel alias zetatau * TODO: */ String TESTINFO_TITLE = "title"; /** * desc element for info element * @author rigel alias zetatau * TODO: */ String TESTINFO_DESC = "desc"; /** * input element for testcase element * @author rigel alias zetatau * TODO: */ String TESTINPUT = "input"; /** * item element for input element * @author rigel alias zetatau * TODO: */ String TESTINPUT_ITEM = "input-item"; /** * id attribute for testcase item * @author rigel alias zetatau * TODO: */ String ATTR_TESTINPUT_ITEM_ID = "id"; /** * type attribute for testcase item * @author rigel alias zetatau * TODO: */ String ATTR_TESTINPUT_ITEM_TYPE = "type"; [...] +++ // ===org.apache.tools.ant.taskdefs.optional.junit.JUnitVersionHelper=== // // Reflection routines used to get testcase annotation info (mantaining JDK1.2 compiler compliance only, not granted correct [EMAIL PROTECTED]) // +++ [...] /** constant for unnnamed testsuites/cases */ private static final String UNKNOWN = "unknown"; private static final String JUNIT_TESTFACADE = "junit.framework.JUnit4TestCaseFacade"; final static int DATA=0,TYPE=1; public static String getTestCaseStringAtt(Test test, String annotationMatch, String annotationParameter) { if (test != null) { if (test.getClass().getName().equals(JUNIT_TESTFACADE)) { String sOut = String.valueOf(helperMethodInvoke(test,annotationMatch,annotationParameter,UNKNOWN)[DATA][0]); if (!sOut.equals(UNKNOWN)) return sOut; } else return ""; } return UNKNOWN; } public static Object[][] getTestCaseStringArrayAtt(Test test, String annotationMatch, String annotationParameter) { if (test != null) { if (test.getClass().getName().equals(JUNIT_TESTFACADE)) { Object[][] rt = helperMethodInvoke(test,annotationMatch,annotationParameter,UNKNOWN); if (rt.length==0) return new Object[0][0]; if (rt.length==0) return new Object[][]{rt[DATA],{}}; rt = new Object[][]{rt[DATA],new Object[rt[DATA].length]}; for (int i=0; i private static Iterator helperDescriptorCollection(Test facade) { final String junitDescription="org.junit.runner.Description", methodOnFacade="getDescription", methodOnItem="getAnnotations"; ArrayList empty = new ArrayList(); if (!facade.getClass().getName().equals(JUNIT_TESTFACADE)) return empty.iterator(); try { Class.forName(junitDescription,false,ClassLoader.getSystemClassLoader()); // otherwise throw an exception Method m = facade.getClass().getMethod(methodOnFacade, new Class[0]); Object itemInstance = m.invoke(facade, new Object[0]); if (itemInstance!=null&&junitDescription.equals(itemInstance.getClass().getName())){ Method m1 = itemInstance.getClass().getMethod(methodOnItem, new Class[0]); Object rtObj = m1.invoke(itemInstance, new Object[0]); if (rtObj instanceof Collection) return ((Collection)rtObj).iterator(); return empty.iterator(); } else return empty.iterator(); } catch (ClassNotFoundException e) { } catch (SecurityException e) { } catch (IllegalArgumentException e) { } catch (NoSuchMethodException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } return empty.iterator(); } private static Object helperAnnotation(Test façade, String annotationMatch) { final String methodOnAnnotation="annotationType"; Object item=null; Iterator it = helperDescriptorCollection(façade); while (it.hasNext()) { Object a = (Object)it.next(); String match = ""; try { Method m = a.getClass().getMethod(methodOnAnnotation, new Class[0]); Class out = (Class)m.invoke(a, new Object[0]); match=String.valueOf(out.getName()); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } if (annotationMatch.equals(match)) { item=a; break; } } return item; } private static Object[][] helperMethodInvoke(Test instance, String annotationMatch, String methodName, String defaultValue) { try { /* * ANNOTATIONS WORKS DOES NOT WORK UNDER JDK 1.5 Iterator it = (junit.framework.JUnit4TestCaseFacade)instance).getDescription().getAnnotations().iterator(); java.lang.annotation.Annotation item=null; while (it.hasNext()) { java.lang.annotation.Annotation a = (java.lang.annotation.Annotation)it.next(); if (annotationMatch.equals(a.annotationType().getName())) { item=a; break; } }*/ Object item = helperAnnotation(instance, annotationMatch); /* No appropriate annotation was found so returns defaultValue */ if (item==null) return new Object[][]{new String[]{defaultValue},{}}; Method m = item.getClass().getMethod(methodName, new Class[0]); Object oOut = m.invoke(item, new Object[0]); if (oOut instanceof String) { String sOut = String.valueOf(oOut); if ("".equals(sOut)||sOut==null) return new Object[][]{new String[]{defaultValue},{}}; else return new Object[][]{new String[]{sOut},{}}; } else if (oOut instanceof String[]) { return new Object[][]{(String[])oOut,{}}; } else if (oOut instanceof Enum) { return new Object[][]{new String[]{String.valueOf(oOut)},{}}; } else { return new Object[][]{new String[]{defaultValue},{}}; } } catch (SecurityException e) { } catch (IllegalArgumentException e) { } catch (NoSuchMethodException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } return new Object[][]{new String[]{defaultValue}}; } public static String predictDataType(Object obj) { String sPlain = String.valueOf(obj); String sPlainType = obj.getClass().getName(); Number nTest=null; try { nTest = new BigDecimal(sPlain); if (nTest.toString().equals(sPlain)) sPlainType=nTest.getClass().getName(); } catch (NumberFormatException e) {} try { nTest = new BigInteger(sPlain); if (nTest.toString().equals(sPlain)) sPlainType=nTest.getClass().getName(); } catch (NumberFormatException e) {} try { nTest = new Double(sPlain); if (nTest.toString().equals(sPlain)) sPlainType=nTest.getClass().getName(); } catch (NumberFormatException e) {} try { nTest = new Long(sPlain); if (nTest.toString().equals(sPlain)) sPlainType=nTest.getClass().getName(); } catch (NumberFormatException e) {} try { nTest = new Float(sPlain); if (nTest.toString().equals(sPlain)) sPlainType=nTest.getClass().getName(); } catch (NumberFormatException e) {} try { nTest = new Integer(sPlain); if (nTest.toString().equals(sPlain)) sPlainType=nTest.getClass().getName(); } catch (NumberFormatException e) {} try { nTest = new Byte(sPlain); if (nTest.toString().equals(sPlain)) sPlainType=nTest.getClass().getName(); } catch (NumberFormatException e) {} try { nTest = new Short(sPlain); if (nTest.toString().equals(sPlain)) sPlainType=nTest.getClass().getName(); } catch (NumberFormatException e) {} return sPlainType; } [...] +++ // ===org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter=== // // Additional tag set inserted into testcase and composed by information retrieved by custom annotation // +++ public void endTest(Test test) { [...] /* * This adds additional info to the generated XML test case data, unfortunately I don't * know what ant helper class can give me some params from XML build */ String sType = JUnitVersionHelper.getTestCaseStringAtt(test,"test.TestInfo",ATTR_TESTTYPE); if (!UNKNOWN.equals(sType)) { currentTest.setAttribute(ATTR_TESTTYPE,sType); } String sTypeId = JUnitVersionHelper.getTestCaseStringAtt(test,"test.TestInfo",ATTR_TESTTYPEID); if (!UNKNOWN.equals(sTypeId)) { currentTest.setAttribute(ATTR_TESTTYPEID,sTypeId); } Element currentTestInfo = doc.createElement(TESTINFO); String sTitle = JUnitVersionHelper.getTestCaseStringAtt(test,"test.TestInfo",TESTINFO_TITLE); if (!UNKNOWN.equals(sTitle)) { CDATASection titleNode = doc.createCDATASection(sTitle); Element currentTestInfoTitle = doc.createElement(TESTINFO_TITLE); currentTestInfoTitle.appendChild(titleNode); currentTestInfo.appendChild(currentTestInfoTitle); } String sDesc = JUnitVersionHelper.getTestCaseStringAtt(test,"test.TestInfo",TESTINFO_DESC); if (!UNKNOWN.equals(sDesc)) { CDATASection descNode = doc.createCDATASection(sDesc); Element currentTestInfoDesc = doc.createElement(TESTINFO_DESC); currentTestInfoDesc.appendChild(descNode); currentTestInfo.appendChild(currentTestInfoDesc); } final int DATA=0, TYPE=1; Object[][] aInput = JUnitVersionHelper.getTestCaseStringArrayAtt(test,"test.TestInfo",TESTINPUT); if (aInput.length>0) { Element currentTestInput = doc.createElement(TESTINPUT); if (aInput[DATA].length>=1) { if (!String.valueOf(aInput[DATA][0]).equals(UNKNOWN)) { for (int i=0; i Element currentTestInputItem = doc.createElement(TESTINPUT_ITEM); currentTestInputItem.setAttribute(ATTR_TESTINPUT_ITEM_ID,String.valueOf(i)); if (aInput[TYPE].length>0) currentTestInputItem.setAttribute(ATTR_TESTINPUT_ITEM_TYPE,String.valueOf(aInput[TYPE][i])); else currentTestInputItem.setAttribute(ATTR_TESTINPUT_ITEM_TYPE,String.class.getName()); CDATASection inputNode = doc.createCDATASection(String.valueOf(aInput[DATA][i])); currentTestInputItem.appendChild(inputNode); currentTestInput.appendChild(currentTestInputItem); } } } currentTestInfo.appendChild(currentTestInput); } currentTest.appendChild(currentTestInfo); [...] } +++ Thank You -- View this message in context: http://www.nabble.com/How-to-retrieve-any-params-from-build.xml-internally-to-the-ant-source-code-environment--tp15391637p15391637.html Sent from the Ant - Dev mailing list archive at Nabble.com.