Get name of currently executing test in JUnit 4 - java

In JUnit 3, I could get the name of the currently running test like this:
public class MyTest extends TestCase
{
public void testSomething()
{
System.out.println("Current test is " + getName());
...
}
}
which would print "Current test is testSomething".
Is there any out-of-the-box or simple way to do this in JUnit 4?
Background: Obviously, I don't want to just print the name of the test. I want to load test-specific data that is stored in a resource with the same name as the test. You know, convention over configuration and all that.

JUnit 4.7 added this feature it seems using TestName-Rule. Looks like this will get you the method name:
import org.junit.Rule;
public class NameRuleTest {
#Rule public TestName name = new TestName();
#Test public void testA() {
assertEquals("testA", name.getMethodName());
}
#Test public void testB() {
assertEquals("testB", name.getMethodName());
}
}

JUnit 4.9.x and higher
Since JUnit 4.9, the TestWatchman class has been deprecated in favour of the TestWatcher class, which has invocation:
#Rule
public TestRule watcher = new TestWatcher() {
protected void starting(Description description) {
System.out.println("Starting test: " + description.getMethodName());
}
};
Note: The containing class must be declared public.
JUnit 4.7.x - 4.8.x
The following approach will print method names for all tests in a class:
#Rule
public MethodRule watchman = new TestWatchman() {
public void starting(FrameworkMethod method) {
System.out.println("Starting test: " + method.getName());
}
};

JUnit 5 and higher
In JUnit 5 you can inject TestInfo which simplifies test metadata injection to test methods. For example:
#Test
#DisplayName("This is my test")
#Tag("It is my tag")
void test1(TestInfo testInfo) {
assertEquals("This is my test", testInfo.getDisplayName());
assertTrue(testInfo.getTags().contains("It is my tag"));
}
See more: JUnit 5 User guide, TestInfo javadoc.

Try this instead:
public class MyTest {
#Rule
public TestName testName = new TestName();
#Rule
public TestWatcher testWatcher = new TestWatcher() {
#Override
protected void starting(final Description description) {
String methodName = description.getMethodName();
String className = description.getClassName();
className = className.substring(className.lastIndexOf('.') + 1);
System.err.println("Starting JUnit-test: " + className + " " + methodName);
}
};
#Test
public void testA() {
assertEquals("testA", testName.getMethodName());
}
#Test
public void testB() {
assertEquals("testB", testName.getMethodName());
}
}
The output looks like this:
Starting JUnit-test: MyTest testA
Starting JUnit-test: MyTest testB
NOTE: This DOES NOT work if your test is a subclass of TestCase! The test runs but the #Rule code just never runs.

Consider using SLF4J (Simple Logging Facade for Java) provides some neat improvements using parameterized messages. Combining SLF4J with JUnit 4 rule implementations can provide more efficient test class logging techniques.
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import org.junit.rules.TestWatchman;
import org.junit.runners.model.FrameworkMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggingTest {
#Rule public MethodRule watchman = new TestWatchman() {
public void starting(FrameworkMethod method) {
logger.info("{} being run...", method.getName());
}
};
final Logger logger =
LoggerFactory.getLogger(LoggingTest.class);
#Test
public void testA() {
}
#Test
public void testB() {
}
}

A convoluted way is to create your own Runner by subclassing org.junit.runners.BlockJUnit4ClassRunner.
You can then do something like this:
public class NameAwareRunner extends BlockJUnit4ClassRunner {
public NameAwareRunner(Class<?> aClass) throws InitializationError {
super(aClass);
}
#Override
protected Statement methodBlock(FrameworkMethod frameworkMethod) {
System.err.println(frameworkMethod.getName());
return super.methodBlock(frameworkMethod);
}
}
Then for each test class, you'll need to add a #RunWith(NameAwareRunner.class) annotation. Alternatively, you could put that annotation on a Test superclass if you don't want to remember it every time. This, of course, limits your selection of runners but that may be acceptable.
Also, it may take a little bit of kung fu to get the current test name out of the Runner and into your framework, but this at least gets you the name.

JUnit 4 does not have any out-of-the-box mechanism for a test case to get it’s own name (including during setup and teardown).

String testName = null;
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
for (int i = trace.length - 1; i > 0; --i) {
StackTraceElement ste = trace[i];
try {
Class<?> cls = Class.forName(ste.getClassName());
Method method = cls.getDeclaredMethod(ste.getMethodName());
Test annotation = method.getAnnotation(Test.class);
if (annotation != null) {
testName = ste.getClassName() + "." + ste.getMethodName();
break;
}
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException e) {
} catch (SecurityException e) {
}
}

Based on the previous comment and further considering I created an extension of TestWather which you can use in your JUnit test methods with this:
public class ImportUtilsTest {
private static final Logger LOGGER = Logger.getLogger(ImportUtilsTest.class);
#Rule
public TestWatcher testWatcher = new JUnitHelper(LOGGER);
#Test
public test1(){
...
}
}
The test helper class is the next:
public class JUnitHelper extends TestWatcher {
private Logger LOGGER;
public JUnitHelper(Logger LOGGER) {
this.LOGGER = LOGGER;
}
#Override
protected void starting(final Description description) {
LOGGER.info("STARTED " + description.getMethodName());
}
#Override
protected void succeeded(Description description) {
LOGGER.info("SUCCESSFUL " + description.getMethodName());
}
#Override
protected void failed(Throwable e, Description description) {
LOGGER.error("FAILURE " + description.getMethodName());
}
}
Enjoy!

In JUnit 5 TestInfo acts as a drop-in replacement for the TestName rule from JUnit 4.
From the documentation :
TestInfo is used to inject information about the current test or
container into to #Test, #RepeatedTest, #ParameterizedTest,
#TestFactory, #BeforeEach, #AfterEach, #BeforeAll, and #AfterAll
methods.
To retrieve the method name of the current executed test, you have two options : String TestInfo.getDisplayName() and
Method TestInfo.getTestMethod().
To retrieve only the name of the current test method TestInfo.getDisplayName() may not be enough as the test method default display name is methodName(TypeArg1, TypeArg2, ... TypeArg3).
Duplicating method names in #DisplayName("..") is not necessary a good idea.
As alternative you could use
TestInfo.getTestMethod() that returns a Optional<Method> object.
If the retrieval method is used inside a test method, you don't even need to test the Optional wrapped value.
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.Test;
#Test
void doThat(TestInfo testInfo) throws Exception {
Assertions.assertEquals("doThat(TestInfo)",testInfo.getDisplayName());
Assertions.assertEquals("doThat",testInfo.getTestMethod().get().getName());
}

JUnit 5 via ExtensionContext
Advantage:
You get to have the added functionalities of ExtensionContext by overriding afterEach(ExtensionContext context).
public abstract class BaseTest {
protected WebDriver driver;
#RegisterExtension
AfterEachExtension afterEachExtension = new AfterEachExtension();
#BeforeEach
public void beforeEach() {
// Initialise driver
}
#AfterEach
public void afterEach() {
afterEachExtension.setDriver(driver);
}
}
public class AfterEachExtension implements AfterEachCallback {
private WebDriver driver;
public void setDriver(WebDriver driver) {
this.driver = driver;
}
#Override
public void afterEach(ExtensionContext context) {
String testMethodName = context.getTestMethod().orElseThrow().getName();
// Attach test steps, attach scsreenshots on failure only, etc.
driver.quit();
}
}

#ClassRule
public static TestRule watchman = new TestWatcher() {
#Override
protected void starting( final Description description ) {
String mN = description.getMethodName();
if ( mN == null ) {
mN = "setUpBeforeClass..";
}
final String s = StringTools.toString( "starting..JUnit-Test: %s.%s", description.getClassName(), mN );
System.err.println( s );
}
};

I usually use something like this:
/** Returns text with test method name
#param offset index of method on call stack to print, 1 for a caller of this method.
*/
static String getName(int offset)
{
Throwable t = new Throwable();
t.fillInStackTrace();
return
t.getStackTrace()[offset].getMethodName()+":"+t.getStackTrace()[offset].getLineNumber();
};
This is exactly what Exception do use when printing stack trace.
Depending on the exact context You may have to figure out correct offset value. It is crude and primitive tough and is not using any fancy modern futures.

I'd suggest you decouple the test method name from your test data set. I would model a DataLoaderFactory class which loads/caches the sets of test data from your resources, and then in your test case cam call some interface method which returns a set of test data for the test case. Having the test data tied to the test method name assumes the test data can only be used once, where in most case i'd suggest that the same test data in uses in multiple tests to verify various aspects of your business logic.

You can achieve this using Slf4j and TestWatcher
private static Logger _log = LoggerFactory.getLogger(SampleTest.class.getName());
#Rule
public TestWatcher watchman = new TestWatcher() {
#Override
public void starting(final Description method) {
_log.info("being run..." + method.getMethodName());
}
};

I have a Junit4 test class that extends TestCase so the example with #Rule didn't work (as mentioned in other answers).
However, if your class extends TestCase you can use getName() to get the current test name so this works:
#Before
public void setUp() {
System.out.println("Start test: " + getName());
}
#After
public void tearDown() {
System.out.println("Finish test: " + getName());
}

A more simpler way is to put this logic in setUp() and tearDown() methods.
Refer below code for better clarity,
import java.lang.reflect.Method;
#BeforeMethod
void setUp(Method method) {
log.info("###############################################");
log.info("Running Test: {}", method.getName());
}
#AfterMethod
void tearDown(Method method) {
log.info("Finished Test: {}", method.getName());
log.info("###############################################");
}
#Test
public void testMethodName() {
// Method logic implementation...
}
Here is the output of above test execution,
#############################################################
Running Test: testMethodName
// Logs related to method execution...
Finished Test: testMethodName
#############################################################

Related

Is there a way, I can fetch the name of current test method running in testNG and use it in the name of screenshot if test fails( in different class)

I am using Reflection Method Class,or also ITestResult Class result to fetch the name of the currently running test,
#AfterMethod
public String getTestMethodName(ITestResult result)
{
return result.getName();
}
Declare a parameter of type ITestResult in your #AfterMethod and TestNG will inject it
#AfterMethod
public void afterMethod(ITestResult result) {
System.out.println("method name:" + result.getMethod().getMethodName());
}
OR
If you want to get the method name before the test is executed you can use the following:
import java.lang.reflect.Method;
#BeforeMethod
public void nameBefore(Method method)
{
System.out.println("Test name: " + method.getName());
}
Whenever you are creating a new object, pass the testcase name to the constructor and initilaize a testcaseName variable with the value from the Test method.
LoginTest.java:
public class LoginTest{
#Test
public void sampleTest(Method method) {
String testcaseName = method.getName();
LoginPageActions loginPageActions = new LoginPageActions(testcaseName);
}
}
LoginPageActions.java:
public class LoginPageActions{
private String testCaseName = null;
public LoginPageActions(String testcaseName) {
this.testCaseName = testcaseName;
}
}

Testing class that insert, update and delete from the db

I have class that has 3 methods: insert, update and delete from the db.
In order to test it in the insert test method I need to use the insert method and after I insert i need to delete what I inserted, but in order to delete I should use the delete method that I also want to test so it didn't make sense to me that I need to use them and also test them.
I hope you understand my problem. Thanks in advance!
You must decide what you want to test. That was you describe, it is an integration test. By a “real” unitTest, you test only your method, and not the System method and not the database.
If you want a unitTest, you have several options. For Example, you work with interfaces and catch your statement before it comes to the database.
Edit 1 - one possibility to implement unit test with interfaces:
You need one interface that implements the method these go to the backend system:
public interface IDatabase{
public returnValue insert(yourParam);
public int update(yourParam);
}
Then you implement your method with the real functions in a class:
public class Database implements IDatabase {
#Override
public returnValue insert(yourParam) {
// do something
return null;
}
#Override
public int update(yourParam){
// do something
return 0;
}
}
This class you call in the main class:
/**
* The real class to do what you want to do.
*/
public class RealClass {
private IDatabase dbInstance = null;
private IDatabase getDbInstance() {
if (dbInstance == null) {
dbInstance = new Database();
}
return dbInstance;
}
protected void setDbInstance(IDatabase dataBase) {
dbInstance = dataBase;
}
public static void main(String[] args) {
getDbInstance().insert(yourParam);
}
}
For the unit test you implement the interface again:
public class UnitTest implements IDatabase {
#Override
public returnValue insert(yourParam) {
// Here can you test your statement and manipulate the return value
return null;
}
#Override
public int update(yourParam){
if (yourParam.containsValue(value1)) {
assertEquals("yourStatement", yourParam);
return 1;
}else if (yourParam.containsValue(value2)) {
assertEquals("yourStatement2", yourParam);
return 5;
}else{
assertTrue(false,"unknown Statement")
}
}
#Test
public void yourTest(){
RealClass.setDbInstance(this);
//Test something
}
}
This is time-consuming to implement, but with this, you are independent from the backend system and you can call the unittest every time without a database.
By default, the order of test methods is not warrantied in JUnit. Nevertheless, as of JUnit 4.11, you can order by the test name, as follows:
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class Test1 {
#Test
public void aInsert() {
System.out.println("first INSERT");
}
#Test
public void bUpdate() throws Exception {
System.out.println("second UPDATE");
}
#Test
public void cDelete() throws Exception {
System.out.println("third DELETE");
}
}

How to display a name/label for each Parameterized Junit test in Eclipse [duplicate]

Is there a way to set my own custom test case names when using parameterized tests in JUnit4?
I'd like to change the default — [Test class].runTest[n] — to something meaningful.
This feature has made it into JUnit 4.11.
To use change the name of parameterized tests, you say:
#Parameters(name="namestring")
namestring is a string, which can have the following special placeholders:
{index} - the index of this set of arguments. The default namestring is {index}.
{0} - the first parameter value from this invocation of the test.
{1} - the second parameter value
and so on
The final name of the test will be the name of the test method, followed by the namestring in brackets, as shown below.
For example (adapted from the unit test for the Parameterized annotation):
#RunWith(Parameterized.class)
static public class FibonacciTest {
#Parameters( name = "{index}: fib({0})={1}" )
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
{ 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
}
private final int fInput;
private final int fExpected;
public FibonacciTest(int input, int expected) {
fInput= input;
fExpected= expected;
}
#Test
public void testFib() {
assertEquals(fExpected, fib(fInput));
}
private int fib(int x) {
// TODO: actually calculate Fibonacci numbers
return 0;
}
}
will give names like testFib[1: fib(1)=1] and testFib[4: fib(4)=3]. (The testFib part of the name is the method name of the #Test).
Looking at JUnit 4.5, its runner clearly doesn't support that, as that logic is buried inside a private class inside the Parameterized class. You could not use the JUnit Parameterized runner, and create your own instead which would understand the concept of names (which leads to the question of how you might set a name ...).
From a JUnit perspective, it would be nice if instead of (or in addition to) just passing an increment, they would pass the comma delimited arguments. TestNG does this. If the feature is important to you, you can comment on the yahoo mailing list referenced at www.junit.org.
I recently came across the same problem when using JUnit 4.3.1. I implemented a new class which extends Parameterized called LabelledParameterized. It has been tested using JUnit 4.3.1, 4.4 and 4.5. It reconstructs the Description instance using the String representation of the first argument of each parameter array from the #Parameters method. You can see the code for this at:
http://code.google.com/p/migen/source/browse/trunk/java/src/.../LabelledParameterized.java?r=3789
and an example of its use at:
http://code.google.com/p/migen/source/browse/trunk/java/src/.../ServerBuilderTest.java?r=3789
The test description formats nicely in Eclipse which is what I wanted since this makes failed tests a lot easier to find! I will probably further refine and document the classes over the next few days/weeks. Drop the '?' part of the URLs if you want the bleeding edge. :-)
To use it, all you have to do is copy that class (GPL v3), and change #RunWith(Parameterized.class) to #RunWith(LabelledParameterized.class) assuming the first element of your parameter list is a sensible label.
I don't know if any later releases of JUnit address this issue but even if they did, I can't update JUnit since all my co-developers would have to update too and we have higher priorities than re-tooling. Hence the work in the class to be compilable by multiple versions of JUnit.
Note: there is some reflection jiggery-pokery so that it runs across the different JUnit versions as listed above. The version specifically for JUnit 4.3.1 can be found here and, for JUnit 4.4 and 4.5, here.
With Parameterized as a model, I wrote my own custom test runner / suite -- only took about half an hour. It's slightly different from darrenp's LabelledParameterized in that it lets you specify a name explicitly rather than relying on the first parameter's toString().
It also doesn't use arrays because I hate arrays. :)
public class PolySuite extends Suite {
// //////////////////////////////
// Public helper interfaces
/**
* Annotation for a method which returns a {#link Configuration}
* to be injected into the test class constructor
*/
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public static #interface Config {
}
public static interface Configuration {
int size();
Object getTestValue(int index);
String getTestName(int index);
}
// //////////////////////////////
// Fields
private final List<Runner> runners;
// //////////////////////////////
// Constructor
/**
* Only called reflectively. Do not use programmatically.
* #param c the test class
* #throws Throwable if something bad happens
*/
public PolySuite(Class<?> c) throws Throwable {
super(c, Collections.<Runner>emptyList());
TestClass testClass = getTestClass();
Class<?> jTestClass = testClass.getJavaClass();
Configuration configuration = getConfiguration(testClass);
List<Runner> runners = new ArrayList<Runner>();
for (int i = 0, size = configuration.size(); i < size; i++) {
SingleRunner runner = new SingleRunner(jTestClass, configuration.getTestValue(i), configuration.getTestName(i));
runners.add(runner);
}
this.runners = runners;
}
// //////////////////////////////
// Overrides
#Override
protected List<Runner> getChildren() {
return runners;
}
// //////////////////////////////
// Private
private Configuration getConfiguration(TestClass testClass) throws Throwable {
return (Configuration) getConfigMethod(testClass).invokeExplosively(null);
}
private FrameworkMethod getConfigMethod(TestClass testClass) {
List<FrameworkMethod> methods = testClass.getAnnotatedMethods(Config.class);
if (methods.isEmpty()) {
throw new IllegalStateException("#" + Config.class.getSimpleName() + " method not found");
}
if (methods.size() > 1) {
throw new IllegalStateException("Too many #" + Config.class.getSimpleName() + " methods");
}
FrameworkMethod method = methods.get(0);
int modifiers = method.getMethod().getModifiers();
if (!(Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new IllegalStateException("#" + Config.class.getSimpleName() + " method \"" + method.getName() + "\" must be public static");
}
return method;
}
// //////////////////////////////
// Helper classes
private static class SingleRunner extends BlockJUnit4ClassRunner {
private final Object testVal;
private final String testName;
SingleRunner(Class<?> testClass, Object testVal, String testName) throws InitializationError {
super(testClass);
this.testVal = testVal;
this.testName = testName;
}
#Override
protected Object createTest() throws Exception {
return getTestClass().getOnlyConstructor().newInstance(testVal);
}
#Override
protected String getName() {
return testName;
}
#Override
protected String testName(FrameworkMethod method) {
return testName + ": " + method.getName();
}
#Override
protected void validateConstructor(List<Throwable> errors) {
validateOnlyOneConstructor(errors);
}
#Override
protected Statement classBlock(RunNotifier notifier) {
return childrenInvoker(notifier);
}
}
}
And an example:
#RunWith(PolySuite.class)
public class PolySuiteExample {
// //////////////////////////////
// Fixture
#Config
public static Configuration getConfig() {
return new Configuration() {
#Override
public int size() {
return 10;
}
#Override
public Integer getTestValue(int index) {
return index * 2;
}
#Override
public String getTestName(int index) {
return "test" + index;
}
};
}
// //////////////////////////////
// Fields
private final int testVal;
// //////////////////////////////
// Constructor
public PolySuiteExample(int testVal) {
this.testVal = testVal;
}
// //////////////////////////////
// Test
#Ignore
#Test
public void odd() {
assertFalse(testVal % 2 == 0);
}
#Test
public void even() {
assertTrue(testVal % 2 == 0);
}
}
You may also want to try JUnitParams: https://github.com/Pragmatists/JUnitParams
from junit4.8.2, you can create your own MyParameterized class by simply copy Parameterized class. change the getName() and testName() methods in TestClassRunnerForParameters.
None of it was working for me, so I got the source for Parameterized and modified it create a a new test runner. I didn't have to change much but IT WORKS!!!
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.Assert;
import org.junit.internal.runners.ClassRoadie;
import org.junit.internal.runners.CompositeRunner;
import org.junit.internal.runners.InitializationError;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.internal.runners.MethodValidator;
import org.junit.internal.runners.TestClass;
import org.junit.runner.notification.RunNotifier;
public class LabelledParameterized extends CompositeRunner {
static class TestClassRunnerForParameters extends JUnit4ClassRunner {
private final Object[] fParameters;
private final String fParameterFirstValue;
private final Constructor<?> fConstructor;
TestClassRunnerForParameters(TestClass testClass, Object[] parameters, int i) throws InitializationError {
super(testClass.getJavaClass()); // todo
fParameters = parameters;
if (parameters != null) {
fParameterFirstValue = Arrays.asList(parameters).toString();
} else {
fParameterFirstValue = String.valueOf(i);
}
fConstructor = getOnlyConstructor();
}
#Override
protected Object createTest() throws Exception {
return fConstructor.newInstance(fParameters);
}
#Override
protected String getName() {
return String.format("%s", fParameterFirstValue);
}
#Override
protected String testName(final Method method) {
return String.format("%s%s", method.getName(), fParameterFirstValue);
}
private Constructor<?> getOnlyConstructor() {
Constructor<?>[] constructors = getTestClass().getJavaClass().getConstructors();
Assert.assertEquals(1, constructors.length);
return constructors[0];
}
#Override
protected void validate() throws InitializationError {
// do nothing: validated before.
}
#Override
public void run(RunNotifier notifier) {
runMethods(notifier);
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public static #interface Parameters {
}
private final TestClass fTestClass;
public LabelledParameterized(Class<?> klass) throws Exception {
super(klass.getName());
fTestClass = new TestClass(klass);
MethodValidator methodValidator = new MethodValidator(fTestClass);
methodValidator.validateStaticMethods();
methodValidator.validateInstanceMethods();
methodValidator.assertValid();
int i = 0;
for (final Object each : getParametersList()) {
if (each instanceof Object[])
add(new TestClassRunnerForParameters(fTestClass, (Object[]) each, i++));
else
throw new Exception(String.format("%s.%s() must return a Collection of arrays.", fTestClass.getName(), getParametersMethod().getName()));
}
}
#Override
public void run(final RunNotifier notifier) {
new ClassRoadie(notifier, fTestClass, getDescription(), new Runnable() {
public void run() {
runChildren(notifier);
}
}).runProtected();
}
private Collection<?> getParametersList() throws IllegalAccessException, InvocationTargetException, Exception {
return (Collection<?>) getParametersMethod().invoke(null);
}
private Method getParametersMethod() throws Exception {
List<Method> methods = fTestClass.getAnnotatedMethods(Parameters.class);
for (Method each : methods) {
int modifiers = each.getModifiers();
if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))
return each;
}
throw new Exception("No public static parameters method on class " + getName());
}
public static Collection<Object[]> eachOne(Object... params) {
List<Object[]> results = new ArrayList<Object[]>();
for (Object param : params)
results.add(new Object[] { param });
return results;
}
}
You can create a method like
#Test
public void name() {
Assert.assertEquals("", inboundFileName);
}
While I wouldn't use it all the time it would be useful to figure out exactly which test number 143 is.
I make extensive use of static import for Assert and friends, so it is easy for me to redefine assertion:
private <T> void assertThat(final T actual, final Matcher<T> expected) {
Assert.assertThat(editThisToDisplaySomethingForYourDatum, actual, expected);
}
For example, you could add a "name" field to your test class, initialized in the constructor, and display that on test failure. Just pass it in as the first elements of your parameters array for each test. This also helps label the data:
public ExampleTest(final String testLabel, final int one, final int two) {
this.testLabel = testLabel;
// ...
}
#Parameters
public static Collection<Object[]> data() {
return asList(new Object[][]{
{"first test", 3, 4},
{"second test", 5, 6}
});
}
A workaround would be to catch and nest all Throwables into a new Throwable with a custom message that contains all information about the parameters. The message would appear in the stack trace.
This works whenever a test fails for all assertions, errors and exceptions as they are all subclasses of Throwable.
My code looks like this:
#RunWith(Parameterized.class)
public class ParameterizedTest {
int parameter;
public ParameterizedTest(int parameter) {
super();
this.parameter = parameter;
}
#Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] { {1}, {2} });
}
#Test
public void test() throws Throwable {
try {
assertTrue(parameter%2==0);
}
catch(Throwable thrown) {
throw new Throwable("parameter="+parameter, thrown);
}
}
}
The stack trace of the failed test is:
java.lang.Throwable: parameter=1
at sample.ParameterizedTest.test(ParameterizedTest.java:34)
Caused by: java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:92)
at org.junit.Assert.assertTrue(Assert.java:43)
at org.junit.Assert.assertTrue(Assert.java:54)
at sample.ParameterizedTest.test(ParameterizedTest.java:31)
... 31 more
When you want the parameter values in test name then you can do something like -
#ParameterizedTest(name="{index} {arguments} then return false" )
#ValueSource(strings = {"false","FALSE"," ","123","abc"})
#DisplayName("When Feature JVM argument is ")
void test_Feature_JVM_Argument_Is_Empty_Or_Blank_Strings_Or_False(String params) {
System.setProperty("FeatureName", params);
assertFalse(Boolean.parseBoolean(System.getProperty("FeatureName")));
}
Test name will look like -
JUnit Test image
Check out JUnitParams as dsaff mentioned, works using ant to build parameterized test method descriptions in the html report.
This was after trying LabelledParameterized and finding that it although it works with eclipse it does not work with ant as far as the html report is concerned.
Cheers,
Since the parameter accessed (e.g. with "{0}" always returns the toString() representation, one workaround would be to make an anonymous implementation and override toString() in each case. For example:
public static Iterable<? extends Object> data() {
return Arrays.asList(
new MyObject(myParams...) {public String toString(){return "my custom test name";}},
new MyObject(myParams...) {public String toString(){return "my other custom test name";}},
//etc...
);
}
Parameterized test is calling toString() internally.
If you create an object wrapper overiding toString(), it will change the names of the test.
Here is an example, I answered in other post.
https://stackoverflow.com/a/67023556/1839360
For a more complex object you may do the following (example with JUnit 4):
#RunWith(Parameterized.class)
public class MainTest {
private static Object[] makeSample(String[] array, int expectedLength) {
return new Object[]{array, expectedLength, Arrays.toString(array)};
}
#Parameterized.Parameters(name = "for input {2} length should equal {1}")
public static Collection<Object[]> data() {
return Arrays.asList(
makeSample(new String[]{"a"}, 1),
makeSample(new String[]{"a", "b"}, 2)
);
}
private final int expectedLength;
private final String[] array;
public MainTest(String[] array, int expectedLength, String strArray) {
this.array = array;
this.expectedLength = expectedLength;
}
#Test
public void should_have_expected_length() {
assertEquals(expectedLength, array.length);
}
}
The trick here is to use one input parameter as a string describing either some part of input or the whole test case.
Before adding third parameter it looked like this
And after like this

How do I test exceptions in a parameterized test?

In JUnit4 you can write parameterized unit tests by providing parameters collection in one method, which will be passed to the constructor of the test and testing in another method. If I have a parameter for which I expect an exception to be thrown, how do I specify that?
this is how i use junit parameterized test with expected exceptions:
#RunWith(Parameterized.class)
public class CalcDivTest {
#Parameter(0)
public int num1;
#Parameter(1)
public int num2;
#Parameter(2)
public int expectedResult;
#Parameter(3)
public Class<? extends Exception> expectedException;
#Parameter(4)
public String expectedExceptionMsg;
#Rule
public ExpectedException thrown = ExpectedException.none();
#Parameters
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] {
// calculation scenarios:
{ 120, 10, 12, null, null }, // simple div
{ 120, 0, -1, ArithmeticException.class, "/ by zero" }, // div by zero
});
}
#Test
public void testDiv() throws CCalculationException {
//setup expected exception
if (expectedException != null) {
thrown.expect(expectedException);
thrown.expectMessage(expectedExceptionMsg);
}
assertEquals("calculation result is not as", expectedResult, div(num1, num2) );
}
private int div(int a, int b) {
return a/b;
}
}
In contrast to what other suggest, I would not introduce any kind of logic to tests - even simple ifs!
What you should have are two testing methods:
first one takes valid parameters (and expects some output)
second takes invalid parameters (and expects exceptions)
Not sure if JUnit with its constructor-based parametrized testing is able to do this. Probably you would have to create two test classes for this. Go with JUnit Params or TestNG which offer much more convenient solution.
I agree with Tomek, and would go with two tests. The first tests for cases where no exceptions are expected. The second tests for values that should result in exceptions being thrown (i.e., and fails if they are not thrown).
Below is a simple example, where the implementation of ExceptionThrower.throwAnInstanceException(int) simply throws an IllegalArgumentException when the supplied int is less-than-1. In your implementation, all supplied values should trigger the exception.
#ParameterizedTest
#ValueSource(ints = {0, 1})
public void parameterizedIntExceptionTest(int testValue) {
ExceptionThrower exceptionThrower = new ExceptionThrower();
assertThrows(IllegalArgumentException.class, () -> {
exceptionThrower.throwAnInstanceException(testValue);
});
}
If you wanted to supply multiple arguments, then you'd be looking at using a MethodSource vice a ValueSource for the test.
if (parameter == EXCEPTION_EXPECTED) {
try {
method(parameter);
fail("didn't throw an exception!");
} catch (ExpectedException ee) {
// Test succeded!
}
}
Gabriel, please look at TestWatcher rule (since JUnit 4.9). Here is the sample code quoted from http://junit-team.github.io/junit/javadoc/4.11/org/junit/rules/TestWatcher.html:
public static class WatchmanTest {
private static String watchedLog;
#Rule
public TestWatcher watchman= new TestWatcher() {
#Override
protected void failed(Throwable e, Description description) {
watchedLog+= description + "\n";
}
#Override
protected void succeeded(Description description) {
watchedLog+= description + " " + "success!\n";
}
};
#Test
public void fails() {
fail();
}
#Test
public void succeeds() {
}
}
Another approach would be to use ErrorCollector from JUnit 4.7:
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void testCollectingErrors() {
thrown.handleAssertionErrors();
thrown.expect(MultipleFailureException.class); // or #expectMessage()/#expectCause()
collector.checkThat("a", equalTo("b"));
//...
}
If you used catch-exception instead of the corresponding annotations and rules of JUnit4, then your code would look like this:
catchException(obj).method(parameter);
if (parameter != EXCEPTION_EXPECTED) {
assert caughtException() instanceof ExpectedException;
}
// more assertions
#Test(expected = Exception.class)
#Parameters(value = { "invalidInput1", "invalidInput2" })
public void shouldThrowOnInvalidInput(String input) {
ClassToTest.methodToTest(input);
}
Using junitparams.Parameters from junitparams library.

To find the number of test methods in a JUnit TestCase

Is there a way to know the number of test methods in a test case?
What I want to do is have a test case which tests several scenarios and for all these i would be doing the data setUp() only once. Similarly I would like to do the cleanup (tearDown()) once at the end of all the test methods.
The current approach i am using is to maintain a counter for the number of test methods that are present in the file and decrement them in the tearDown method and do the cleanup when the count reaches 0. But this counter needs to be taken care of whenever new test methods are added.
Instead of using setup/teardown you should probably use methods annotated with #BeforeClass and #AfterClass instead.
You can do this through #BeforeClass and #AfterClass in JUnit4:
http://junit.org/apidocs/org/junit/BeforeClass.html
Volker
Here is the piece of code I wrote to find all the test cases in my JUnit project. What it does is reads the files(under package mentioned in code) and using reflection APIs, finds the test cases with annotations "#Test" and also the ones which start with "test" but don't have the #Test annotation
public class TestCaseCount {
private static List<Class> getClasses(String packageName)
throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
List<File> dirs = new ArrayList<File>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
ArrayList<Class> classes = new ArrayList<Class>();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes /* .toArray(new Class[classes.size()]) */;
}
private static List<Class> findClasses(File directory, String packageName)
throws ClassNotFoundException {
List<Class> classes = new ArrayList<Class>();
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
assert !file.getName().contains(".");
classes.addAll(findClasses(file, packageName + "." + file.getName()));
} else if (file.getName().endsWith(".class")) {
classes.add(Class.forName(packageName + '.'
+ file.getName().substring(0, file.getName().length() - 6)));
}
}
return classes;
}
public static void main(String args[]) {
ArrayList<Class> classes = new ArrayList<Class>();
try {
// Feature1 Test Cases
classes.addAll(TestCaseCount.getClasses("mypackage.feature1.tests"));
// Feature2 Test Cases
classes.addAll(TestCaseCount.getClasses("mypackage.feature2.tests1"));
classes.addAll(TestCaseCount.getClasses("mypackage.feature2.tests2"));
// Feature3 Test Cases
classes.addAll(TestCaseCount.getClasses("mypackage.feature3.tests"));
} catch (Exception e) {
e.printStackTrace();
}
int testcaseCount = 0;
for (Class cl : classes) {
System.out.println("Test Class Name : " + cl.getName());
Method[] methods = cl.getDeclaredMethods();
for (Method method : methods) {
Annotation[] annotations = method.getDeclaredAnnotations();
if (annotations.length == 0 && method.getName().startsWith("test")) {
testcaseCount++;
} else {
for (Annotation annotation : annotations) {
if (annotation.annotationType().toString()
.equals("interface org.junit.Test")) {
testcaseCount++;
}
}
}
}
}
System.out.println("Total Test Cases " + testcaseCount);
}
}
Short example for counting tests with #BeforeClass, #AfterClass and #Before.
public class CountTest {
static int count;
#BeforeClass
public static void beforeClass() {
count = 0;
}
#Before
public void countUp() {
count++;
}
#AfterClass
public static void printCount() {
System.out.println(count + " tests.");
}
#Test
public void test1() {
assertTrue(true);
}
// some more tests
Output will be, e.g.:
5 tests.
If you are using Junit4 and the suggestion given by others is the correct one. But if you using earlier version then use this technique to achieve what you want -
You can define a suite for all those tests for which you want to setup and teardown only once. Take a look at junit.extensions.TestSetup class. Instead of executing your test classes you need to then execute these suites.
A solution for junit 3 is to call a special setup method in every test which checks a static flag. if the flag is not set, run the global setup. If it is, skip the setup.
Make sure the global setup is properly synchronized if you want to run tests in parallel.
Using #Rules on TestWatcher you can take note of count and many other things like method name etc. You can override these methods and use .
#Override
public Statement apply(Statement base, Description description){
return super.apply(base, description);
}
#Override
protected void failed(Throwable e, Description description) {
failed.add(description);
LogUtil.error("[FAILED] "+description.getMethodName()+" [Test Failed]"+e.getMessage());
super.failed(e, description);
}
#Override
protected void finished(Description description) {
LogUtil.info("[FINISHED] "+description.getMethodName());
super.finished(description);
}
#Override
protected void skipped(AssumptionViolatedException e,Description description) {
LogUtil.error("[FAILED] Test Failed due to Assumption Voilation "+e.getMessage());
super.skipped(e,description);
}
#Override
protected void starting(Description description) {
LogUtil.info("-----------------------------------------------------------");
LogUtil.info("[STARTED] "+description.getMethodName());
super.starting(description);
}
#Override
protected void succeeded(Description description) {
passed.add(description);
LogUtil.info("[PASSED] "+description.getMethodName());
super.succeeded(description);
}
In your Junit Testcase Use
#Rule
public TestRule watcher = new TestWatcherChild();

Categories

Resources