How to obtain test case name in JUnit 4 at runtime? [duplicate] - java

This question already has answers here:
Get name of currently executing test in JUnit 4
(17 answers)
Closed 9 years ago.
I want to do some logging while executing my JUnit test. In JUnit 3.x it was always easy to obtain the name of the currently running test case, no matter how the test case was instantiated:
public void testFoo() throws Exception() {
String testName = this.getName();
// [...] do some stuff
}
In JUnit 4 things seem to be not so easy. Does anyone know a solution to this? Is there any option to reflect into the current Runner instance?

In JUnit 4.7, you can also get the name of the currently executed test method. May be nice when logging.
Taken from JUnit 4.7 Release Notes (read them here at github) :
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());
}
}

OK. I've found another approach [somewhere on the Internet](http://www.nabble.com/What-happened-to-getName()--td23456371.html):
#RunWith(Interceptors.class)
public class NameTest {
#Interceptor public TestName name = new TestName();
#Test public void funnyName() {
assertEquals("funnyName", name.getMethodName());
}
}

public class FooTest {
#Rule
final public TestRule traceTestWatcher = new TestWatcher() {
#Override
protected void starting(Description d) {
System.out.println(d);
}
};
#Test
public void testBar() {
...
}
#Test
public void testBaz() {
...
}
}

What's wrong with:
#Test
public void foo() throws Exception() {
String testName = this.getName();
// [...] do some stuff
}
?

I know this is old, but here is a useful (non-junit) method that I put at the top of all my tests.
public static void printTestName(){
final StackTraceElement[] ste = new Throwable().getStackTrace();
int buffer = 35 - ste[1].getMethodName().length();
System.out.println("*******************************************************");
System.out.println("* TEST: " + ste[1].getMethodName() + getBuffer(buffer) + "*");
System.out.println("*******************************************************");
}
private static String getBuffer(int offset){
StringBuilder buffer = new StringBuilder("");
for(int i = 1; i < offset; i++){
buffer.append(" ");
}
return buffer.toString();
}

Related

Junit - how Java deals with class methods having Asserts

I a quite new to Junit. I have a question on how Java runs Junit classes. I have a code like this
public class TestJunit1 {
String message = "Srinivas";
MessageUtil messageutil = new MessageUtil(message);
#Test
public void testPrintMessage() {
System.out.println("Inside testPrintMessage");
assertEquals(message, messageutil.printMessage());
}
}
public class TestJUnit5 extends TestCase {
protected double fValue1;
protected double fValue2;
#Before
public void setUp() throws Exception {
fValue1 = 2.0;
fValue2 = 3.0;
}
#Test
public void testAdding() {
System.out.println("No of test cases =" + this.countTestCases());
String name = this.getName();
System.out.println("Test Case name is: "+name);
this.setName("methodNewAdd");
String newName = this.getName();
System.out.println("New name of the test case is:"+newName);
System.out.println(this.getClass());
}
#After
public void tearDown() throws Exception {
}
public class TestSuiteDemo {
public static void main(String[] args) {
TestSuite ts = new TestSuite(TestJunit1.class, TestJunit2.class, TestJUnit5.class);
TestResult tr = new TestResult();
ts.run(tr);
System.out.println("Number of test cases is:"+tr.runCount());
}
}
when I run TestSuiteDemo as Java application in eclipse, it produces output from println statements from TestJUnit5 and not from TestJunit1.
Could somebody please explain why this happens?
Regards
Srinivas
Because TestJUnit5 extends a TestCase (not TestJunit1) so JUnit sees the test case and runs it.
From the junit.framework.TestSuite code, any class that inherits Test class or extends TestCase can get registered with TestSuite constructor.
private void addTestsFromTestCase(final Class<?> theClass) {
fName = theClass.getName();
try {
getTestConstructor(theClass); // Avoid generating multiple error messages
} catch (NoSuchMethodException e) {
addTest(warning("Class " + theClass.getName() + " has no public constructor TestCase(String name) or TestCase()"));
return;
}
if (!Modifier.isPublic(theClass.getModifiers())) {
addTest(warning("Class " + theClass.getName() + " is not public"));
return;
}
Class<?> superClass = theClass;
List<String> names = new ArrayList<String>();
while (Test.class.isAssignableFrom(superClass)) {
for (Method each : MethodSorter.getDeclaredMethods(superClass)) {
addTestMethod(each, names, theClass);
}
superClass = superClass.getSuperclass();
}
if (fTests.size() == 0) {
addTest(warning("No tests found in " + theClass.getName()));
}
}
To get TestJunit1 to work, you will have to create an annotative Suite.
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestJunit1.class,
TestJunit2.class,
TestJunit5.class
})
public class JunitTestSuite {
}
And to run it locally:
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
public class JunitTestSuiteRunner {
public static void main(String[] args) {
Result result = JUnitCore.runClasses(JunitTestSuite.class);
for (Failure fail : result.getFailures()) {
System.out.println(fail.toString());
}
if (result.wasSuccessful()) {
System.out.println("All tests finished successfully...");
}
}
}
I hope this helps.
Source reference.
amoq reference to the stackoverflow post JUnit confusion: use 'extends TestCase' or '#Test'?
is accurate. There are two main way for junit test to recognize and run your rest Junit version 3 , extend test case . Junit version 4 annotate with #Test.
Since your test 1 has neither it is not run at all. Confirm the version of junit your eclipse is using, you could use the annotation version #Test which u might find more pleasant

How to load a different resource with different unit test methods?

I have about 15 JUnit test cases each one which needs a difference resource file from which it reads necessary input data. Currently, I'm hard coding the specific resource file path in each test case method.
#Test
public void testCase1() {
URL url = this.getClass().getResource("/resource1.txt");
// more code here
}
#Test
public void testCase2() {
URL url = this.getClass().getResource("/resource2.txt");
// more code here
}
May be I could have all these files loaded in the setUp() method into separate URL variables and then use the specific URL variable in each test method. Is there a way better way of doing this?
You can use the TestName rule.
#Rule public TestName testName = new TestName();
public URL url;
#Before
public void setup() {
String resourceName = testName.getMethodName().substring(4).toLowerCase();
url = getClass().getResource("/" + resourceName + ".txt");
}
#Test
public void testResource1() {
// snip
}
#Test
public void testResource2() {
// snip
}
Try JUnit RunWith(Parameterized.class).
Example, that takes a resource name and an int expected result :
#RunWith(Parameterized.class)
public class MyTest {
#Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{"resource1.txt", 0000}, {"resource2.txt", 9999}
});
}
public final URL url;
public final int expected;
public MyTest(String resource, int expected) {
this.url=URL url = this.getClass().getResource("/"+resource)
this.expected = expected;
}
#Before
public void setUp() {
}
#Test
public void testReadResource() throws Exception {
// more code here, based on URL and expected
}
}
More info here:http://junit.org/apidocs/org/junit/runners/Parameterized.html

Passing parameter to #Before setup in jUnit test [duplicate]

This question already has answers here:
Is it possible to use different #Before #After for each test case in JUnit?
(2 answers)
Closed 8 years ago.
Is there any way to avoid calling populateRandomData() method at the begining of each test without having a fixed parameter 100. I need to call the same method to setup data before execution of each test but I need to change the number of test data entries e.g. 100 in each case .
public class Tester
{
#Before
public void setUp() {
populateRandomData(100)
}
#Test
public void testMethod() {
}
private void populateRandomData(n){
//n times insert random data in table.
}
}
You can create Parameterized JUnit Test which allows you to add number of parameters you want to pass in unit test case. Have a look at example tutorial Create Parameterized Test Case.
OR
#Rule, using this annotations on your test methods to parameterize the execution of your rules makes it even more useful. Taken from JUnit 4.7 #Rules
EDIT :
Example of Using #Rule :
Below is the class which allows you to initialize different value of num variable which will be used in test method :
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class Test1 implements TestRule {
private final int num;
public Test1(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public class Test1Statement extends Statement {
private final Statement statement;
public Test1Statement(Statement statement, int num) {
this.statement = statement;
}
#Override
public void evaluate() throws Throwable {
statement.evaluate();
}
}
#Override
public Statement apply(Statement statement, Description description) {
return new Test1Statement(statement, num);
}
}
The class below is the actual test case class. It contains JUnit test cases & set value of num variable in test method.
import org.junit.Rule;
import org.junit.Test;
public class RuleNumberTester {
#Rule
public Test1 test = null;
#Rule
public Test1 test1 = null;
#Test
public void num1Test() {
test = new Test1(111);
System.out.println("Num 1 : " + test.getNum());
}
#Test
public void num2Test() {
test1 = new Test1(222);
System.out.println("Num 2 : " + test1.getNum());
}
}
Output :
Test cases are executed successfully & shows the values of num variable which was initialized in test methods on console.
Num 1 : 111
Num 2 : 222
I suppose you could use a #Rule to ensure populateRandomData() is called each time with the correct parameters.
However, this gets ugly quickly since you then need to maintain a list of test method names.
private static final Map<String, Integer> dataCounts = new HashMap<>();
static {
// list (or otherwise obtain) counts here
dataCounts.put("testMethod", 100);
}
#Rule
public TestWatcher watcher = new TestWatcher() {
#Override
protected void starting(Description description) {
Integer count = dataCounts.get(description.getMethodName());
assertNotNull(count);
populateRandomData(count.intValue());
};
};

JMockit: How to override already mocked method with a new mock?

I think I might have found a bug in JMockit, but I would like some to confirm whether it's a bug or there's something I'm missing.
I have the following (very simple) class:
public class Dummy {
public void foo() {System.out.println("O");}
}
Now I have the following tests, where in each of them I try to mock the method 'foo' more than once (each test does it a little differently):
Test #1
#Test
public void test1() {
new MockUp<Dummy>() {
#Mock
public void foo(Invocation inv) {
System.out.println("A");
inv.proceed();
}
}
new MockUp<Dummy>() {
#Mock
public void foo(Invocation inv) {
System.out.println("B");
inv.proceed();
}
}
new Dummy().foo();
}
Test #2
#Test
public void test2() {
mock("A");
mock("B");
new Dummy().foo();
}
private void mock(final String s) {
new MockUp<Dummy>() {
#Mock
public void foo(Invocation inv) {
System.out.println(s);
inv.proceed();
}
}
}
The only difference between the tests is the extraction of the mock code to a different method. But the results are not the same...
Test #1 output:
B
A
B
O
This is odd, because I wouldn't expect A to appear at all. But anyway, here's test #2 output:
B
A
A
A
...ad infinitum
Test #2 will fail with a StackOverflowError.
Is this a bug or am I missing something?
Update (with the solution)
As #Rogério mentioned, this behavior is not acceptable.
Then how can the mock be overridden? like this:
private MockUp<Dummy> mock;
#Test
public void test3() {
mockCorrectly("A");
mockCorrectly("B");
new Dummy().foo();
}
private void mockCorrectly(final String s) {
if (mock != null) {
mock.tearDown();
}
mock = new MockUp<Dummy> {
#Mock
public void foo(Invocation inv) {
System.out.println(s);
inv.proceed();
}
}
}
And for the output:
B
O
Great :)
It's not clear what exactly happens here; apparently, at runtime some "chained mocking" is occurring.
The real problem is that both tests are doing something invalid with the MockUp API: they are mocking the same method in the same class twice in the same test. It is ok to have two different mock-ups for the same class in the same test, as long as they mock different methods/constructors.
The resulting behavior is undefined, as JMockit does not support multiple simultaneous mockings of the same method.

junit4 creating test suite with specific test methods

In junit4 I want to execute specific test methods from different classes i.e want create a test suite with specific test methods from different classes.
Lets say I have 2 classes:
public class Test_Login {
#Test
public void test_Login_001(){
System.out.println("test_Login_001");
}
#Test
public void test_Login_002(){
System.out.println("test_Login_002");
}
#Test
public void test_Login_003(){
System.out.println("test_Login_003");
}
}
public class Logout {
#Test
public void test_Logout_001(){
System.out.println("test_Logout_001");
}
#Test
public void test_Logout_002(){
System.out.println("test_Logout_002");
}
#Test
public void test_Logout_003(){
System.out.println("test_Logout_003");
}
}
From the above classes I want to execute test methods test_Login_001 , test_Login_003 , test_Logout_002 only.
How this can be achieved in junit4 ?
Since JUnit 4.8 introduced Categories there exists a clean solution, create a TestSuite:
#RunWith(Categories.class)
#IncludeCategory(MustHaveTests.class)
#SuiteClasses( { Test_Login.class, Test_Logout.class })
public class MustHaveTestsTestSuite {
public interface MustHaveTests { /* category marker */ }
}
And add the #Category(MustHaveTests.class) above every test you would like to run with the TestSuite, e.g.:
#Category(MustHaveTests.class)
#Test
public void test_Login_001(){
System.out.println("test_Login_001");
}
When running the TestSuite only the MustHaveTests-"tagged" tests will be executed. More Details on #Category: https://github.com/junit-team/junit4/wiki/categories
You need to create an org.junit.runner.Request and pass it to the JunitCore runner, or actually to any Runner.
JUnitCore junitRunner = new JUnitCore();
Request request = Request.method(Logout.class, "test_Logout_002");
Result result = junitRunner.run(request);
I actually created an Annotation and can search for methods with those annotations and dynamically create Request and run them
public class TestsSuite {
public static void main(String[] args) throws Exception {
Class annotation = MyTestAnnotation.class;
JUnitCore junitRunner = new JUnitCore();
Class testClass = Test_Login.class;
Method[] methods = testClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(annotation)) {
if (method.isAnnotationPresent(org.junit.Test.class)) {
Request request = Request.method(testClass, method.getName());
Result result = junitRunner.run(request);
System.out.println(result.wasSuccessful());
}
}
}
}
}
This might not be the slickest implementation, but I solved a similar problem by created a new #SuiteMethods annotation as follows:
SuiteMethods.java
#Retention(RUNTIME)
#Target(TYPE)
public #interface SuiteMethods {
String[] value() default {""};
}
FilteredSuite.java
public class FilteredSuite extends Categories {
private static String[] TEST_METHODS_TO_RUN = {""}; // default behavior is to run all methods
private static Class<?> extractMethodNamesFromAnnotation(Class<?> clazz) {
SuiteMethods methodsAnnotation = clazz.getAnnotation(SuiteMethods.class);
if (methodsAnnotation != null) {
// if our MethodsAnnotation was specified, use it's value as our methods filter
TEST_METHODS_TO_RUN = methodsAnnotation.value();
}
return clazz;
}
public static Filter getCustomFilter() {
Filter f = new Filter() {
#Override
public boolean shouldRun(Description desc) {
String methodName = desc.getMethodName();
for (String subString : TEST_METHODS_TO_RUN) {
if (methodName == null || methodName.contains(subString)) {
return true;
}
}
return false;
}
#Override
public String describe() {
return null;
}
};
return f;
}
public FilteredSuite(Class<?> arg0, RunnerBuilder arg1) throws InitializationError {
super(extractMethodNamesFromAnnotation(arg0), arg1);
}
#Override
public void filter(Filter arg0) throws NoTestsRemainException {
// At test suite startup, JUnit framework calls this method to install CategoryFilter.
// Throw away the given filter and install our own method name filter
super.filter(getCustomFilter());
}
}
A Usage Example
#RunWith(FilteredSuite.class)
#SuiteClasses({
GroupRestTest.class,
ScenarioRestTest.class
})
#SuiteMethods({
"testReadOnlyFlag",
"testSheetWriteData",
"testAddScenarioMeta"
})
public class SubsetTestSuite {
}

Categories