Overview
In this tutorial, we will create an Java Test class with multiple Test Cases, implemented in Java.
Description
The test case validates a Calculator class and exploits some TestNG features such as the ability of validating the same Test against multiple input values, and also the possibility of linking Tests with requirements in Jira using NUnit's Test attributes.
Example 1: Using TestNG standard capabilities
This examples uses the standard built-in TestNG capabilities, without making use of TestNG's advanced features such as annotations (which in turn would require specific code to handle them).
The test class provides some methods marked with the @Test annotation and in some of them additional meta-information is added to the results using the ITestResult object.
Xray is able to process TestNG's ITestResult custom attributes named "test", "requirement" and "labels". Whenever specified, they will allow Xray to identify an existing Xray Test issue to report results to, the requirement to link to and additional labels to add to the Test issue, respectively.
Example 2: Using TestNG annotation capabilities
This examples uses some of the advanced TestNG capabilities, namely the annotation mechanism.
We'll use a specific "Xray" annotation in order to quickly, and in a more elegant way, provide additional meta-information (i.e. "test", "requirement" and "labels") to the Test result, without having to use the ITestResult object in the Test method's code. Whenever specified, they will allow Xray to identify an existing Xray Test issue to report results to, the requirement to link to and additional labels to add to the Test issue, respectively.
package com.xpand.annotations; import java.lang.reflect.Method; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestNGMethod; import org.testng.ITestResult; /** * The listener interface for receiving Xray events. * The Listener can be automatically invoked when TestNG tests are run by using ServiceLoader mechanism. * You can also add this listener to a TestNG Test class by adding * <code>@Listeners({com.xpand.java.XrayAnnotationListener.class})</code> * before the test class * * @see Xray */ public class XrayListener implements IInvokedMethodListener, ITestListener { String requirement = null; String test = null; String labels = null; boolean testSuccess = true; /* (non-Javadoc) * @see org.testng.IInvokedMethodListener#beforeInvocation(org.testng.IInvokedMethod, org.testng.ITestResult) */ public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { if(method.isTestMethod() && annotationPresent(method, Xray.class) ) { testResult.setAttribute("requirement", requirement); testResult.setAttribute("test", test); testResult.setAttribute("labels", labels); } } private boolean annotationPresent(IInvokedMethod method, Class clazz) { boolean retVal = method.getTestMethod().getConstructorOrMethod().getMethod().isAnnotationPresent(clazz) ? true : false; return retVal; } /* (non-Javadoc) * @see org.testng.IInvokedMethodListener#afterInvocation(org.testng.IInvokedMethod, org.testng.ITestResult) */ public void afterInvocation(IInvokedMethod method, ITestResult testResult) { if(method.isTestMethod()) { if( !testSuccess ) { testResult.setStatus(ITestResult.FAILURE); } } } public void onTestStart(ITestResult result) { // TODO Auto-generated method stub } public void onTestSuccess(ITestResult result) { // TODO Auto-generated method stub } public void onTestFailure(ITestResult result) { // TODO Auto-generated method stub } public void onTestSkipped(ITestResult result) { // TODO Auto-generated method stub } public void onTestFailedButWithinSuccessPercentage(ITestResult result) { // TODO Auto-generated method stub } public void onStart(ITestContext context) { for(ITestNGMethod m1 : context.getAllTestMethods()) { if(m1.getConstructorOrMethod().getMethod().isAnnotationPresent(Xray.class)) { //capture metadata information. requirement = m1.getConstructorOrMethod().getMethod().getAnnotation(Xray.class).requirement(); test = m1.getConstructorOrMethod().getMethod().getAnnotation(Xray.class).test(); labels = m1.getConstructorOrMethod().getMethod().getAnnotation(Xray.class).labels(); } } } public void onFinish(ITestContext context) { // TODO Auto-generated method stub } }
{ "version": "1.0.0-*", "buildOptions": { "debugType": "portable", "emitEntryPoint": true }, "dependencies": { "NUnit": "3.5.0", "dotnet-test-nunit": "3.4.0-beta-2" }, "testRunner": "nunit", "frameworks": { "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "type": "platform", "version": "1.1.0" } }, "imports": "dnxcore50" } } }
After successfully running the Test Case and generating the NUnit XML report (e.g., TestResult.xml), it can be imported to Xray (either by the REST API or through the Import Execution Results action within the Test Execution).
NUnit's Test Case is mapped to a Generic Test in Jira, and the Generic Test Definition field contains the namespace, the name of the class, and the method name that implements the Test case.
The Execution Details of the Generic Test contains information about the context, which in this case corresponds to the Test case method, along with the different input values that were validated.
It can also be seen that the Test "CanAddNumbers" was automatically linked to the sum requirement (i.e., the user story "CALC-1").