When I create an and run unit-test, (in Eclipse (Galileo) with JUnit 4.5 or 4.82),
the #Before is never executed (?).
Below is some sample-code. I would expect the output to be :
initialize
testGetFour
But it is just :
testGetFour
#BeforeClass and #AfterClass are never executed either.
Can someone tell me how come ?
public class SomeClass
{
public static int getFour()
{
return 4;
}
}
//---
import org.junit.Before;
import org.junit.Test;
import junit.framework.TestCase;
public class TestSomeClass extends TestCase
{
#Before
public void initialize() // This method will never execute (?!).
{
System.err.println("initialize");
}
#Test
public void testGetFour()
{
System.err.println("testGetFour");
assertEquals(4, SomeClass.getFour());
}
}
Because you're extending TestCase. This is a JUnit3 class, and so Eclipse treats it as such. JUnit 4 does not require the test class to extend anything.
Remove that, it should work fine.
You should not extend from TestCase (JUnit 3 way of using JUnit) and it will work.
Related
I have such an example of test suite class to run many test classes at once in JUnit 4.13.
#RunWith(Suite.class)
#SuiteClasses({
FirstTest.class,
SecondTest.class
})
#TestSuiteAnnotation
public class TestSuite {
}
These are my test classes.
#FirstAnnotation
public class FirstTest extends ExtTest {
#Test
public void test() {
}
}
#SecondAnnotation
public class SecondTest extends ExtTest {
#Test
public void test() {
}
}
public class ExtTest {
#Before
public void beforeMethod() {
System.out.println("Annotations from " + this.getClass());
Arrays.asList(this.getClass().getAnnotations()).forEach(System.out::println);
}
}
When I run test from TestSuite.class, the console output is:
Annotations from class FirstTest
#FirstAnnotation()
Annotations from class SecondTest
#SecondAnnotation()
Currently, this.getClass().getAnnotations() returns annotations from test classes (i.e. FirstTest.class, SecondTest.class). I want to obtain annotation #TestSuiteAnnotation, when I run tests from TestSuite.class.
The expected output should be:
Annotations from class FirstTest
#FirstAnnotation()
#TestSuiteAnnotation()
Annotations from class SecondTest
#SecondAnnotation()
#TestSuiteAnnotation()
Can I somehow obtain annotation #TestSuiteAnnotation, when I run tests from TestSuite.class?
You have multiple options:
JUnit 4 run listener
On JUnit 4, you can register a RunListener, like #nrainer said. If you build with Maven, it is easy to register a run listener like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<includes>
<include>org.acme.TestSuite</include>
</includes>
<properties>
<property>
<name>listener</name>
<value>org.acme.SuiteRunListener</value>
</property>
</properties>
</configuration>
</plugin>
The run listener can override the events testSuiteStarted and testSuiteFinished and either directly log the annotations you are interested in or assign them to a static thread-local variable like private static ThreadLocal<List<Annotation>> currentSuiteAnnotations in testSuiteStarted, then unassign it again in testSuiteFinished.
This works nicely from Maven, I tested it. Unfortunately, there is no direct support for running tests with run listeners from IDEs like IntelliJ IDEA or Eclipse. So if you want to avoid running the tests manually from a class with a main method as shown here, because it would take away all the nice IDE test reporting with drill-down from suite to test class to test method, this is not an option.
JUnit 5 test execution listener
Similar to JUnit 4's run listener, you can register a TestExecutionListener for your JUnit 5 tests. The advantage in JUnit 5 is that you can register it globally via Java's s ServiceLoader mechanism, i.e. it will be picked up when bootstrapping JUnit and should also work in IDEs. I did something similar with another type of extension, and it worked nicely in IntelliJ IDEA and of course also in Maven.
JUnit 4 with custom suite runner
Coming back to JUnit 4, we can extend the first approach with the run listener by declaring a special type of suite. You simply use that suite instead of org.junit.runners.Suite and can enjoy the working run listener in both Maven and the IDE. It works like that, see also my MCVE on GitHub for your convenience:
package org.acme;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunListener;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.stream.Collectors;
public class SuiteRunListener extends RunListener {
private static ThreadLocal<String> currentSuiteName = new ThreadLocal<String>();
private static ThreadLocal<List<Annotation>> currentSuiteAnnotations = new ThreadLocal<>();
#Override
public void testSuiteStarted(Description description) throws Exception {
super.testSuiteStarted(description);
final RunWith runWith = description.getAnnotation(RunWith.class);
if (runWith != null && runWith.value().equals(SuiteWithListener.class)) {
currentSuiteName.set(description.getDisplayName());
currentSuiteAnnotations.set(
description.getAnnotations().stream()
.filter(annotation -> {
final Class<? extends Annotation> annotationType = annotation.annotationType();
return !(annotationType.equals(RunWith.class) || annotationType.equals(SuiteClasses.class));
})
.collect(Collectors.toList())
);
}
}
#Override
public void testSuiteFinished(Description description) throws Exception {
super.testSuiteFinished(description);
final RunWith runWith = description.getAnnotation(RunWith.class);
if (runWith != null && runWith.value().equals(SuiteWithListener.class)) {
currentSuiteName.set(null);
currentSuiteAnnotations.set(null);
}
}
public static String getCurrentSuiteName() {
return currentSuiteName.get();
}
public static List<Annotation> getCurrentSuiteAnnotations() {
return currentSuiteAnnotations.get();
}
}
package org.acme;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.RunnerBuilder;
import java.util.List;
public class SuiteWithListener extends Suite {
public SuiteWithListener(Class<?> klass, RunnerBuilder builder) throws InitializationError {
super(klass, builder);
}
public SuiteWithListener(RunnerBuilder builder, Class<?>[] classes) throws InitializationError {
super(builder, classes);
}
protected SuiteWithListener(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
super(klass, suiteClasses);
}
protected SuiteWithListener(RunnerBuilder builder, Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
super(builder, klass, suiteClasses);
}
protected SuiteWithListener(Class<?> klass, List<Runner> runners) throws InitializationError {
super(klass, runners);
}
#Override
public void run(RunNotifier notifier) {
notifier.addListener(new SuiteRunListener()); // !!!
super.run(notifier);
}
}
package org.acme;
import org.junit.runner.RunWith;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(SuiteWithListener.class) // !!!
#SuiteClasses({
FirstTest.class,
SecondTest.class
})
#TestSuiteAnnotation
public class TestSuite {}
package org.acme;
import org.junit.Before;
import java.util.Arrays;
public class ExtTest {
#Before
public void beforeMethod() {
String currentSuiteName = SuiteRunListener.getCurrentSuiteName();
if (currentSuiteName != null) {
System.out.println("Annotations from suite " + currentSuiteName);
SuiteRunListener.getCurrentSuiteAnnotations().forEach(System.out::println);
}
System.out.println("Annotations from class " + this.getClass());
Arrays.asList(this.getClass().getAnnotations()).forEach(System.out::println);
System.out.println();
}
}
Now when running your suite, you should see output like this:
Annotations from suite org.acme.TestSuite
#org.acme.TestSuiteAnnotation()
Annotations from class class org.acme.FirstTest
#org.acme.FirstAnnotation()
Annotations from suite org.acme.TestSuite
#org.acme.TestSuiteAnnotation()
Annotations from class class org.acme.SecondTest
#org.acme.SecondAnnotation()
Please note: I was assuming that you really need access to the current suite from each single test method, not just at the test class or suite level. If you do not need that and it is enough to let the run listener do something when a suite is started and/or finished, of course you do not need the getter methods for current suite name and suite annotations. I just extended your own example.
I am using SpringJUnit4ClassRunner to run my Integration test case.
Now I am loading the data's to In memory HSQL for each junit test case in #Before method and Destroy it in #After method in Junit Test class.
I need to have data load should happen only once for all test case reside inside test folder . Also should be destroyed after completion of all test case.
I am using Maven for build,JDK8,Spring 4.2.5 and HSQL in memory.
Kindly help me to achieve this logic.
Yes it's possible using JUnit - Suite Test
Create your Test Suite including all the necessary test classes. Configure your setup and teardown methods here
package com.test;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses({Test1.class, Test2.class})
public class TestSuite {
#BeforeClass
public static void setUp() {
// Set up database
}
#AfterClass
public static void tearDown() {
// Cleanup codes
}
}
And create your test classes normally
package com.test;
import org.junit.Test;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:context.xml" })
public class Test1 {
#Test
public void test1() {
System.out.println("test1");
}
}
The questions Debug Partial Mock in JMockit and Debugging Java code tested with Spock and JMockit already deal with the issue, that breakpoints in your software under test (SUT) get ignored when the class gets redefined/instrumented by JMockit.
The recommended solution is that you should add an additional breakpoint in your testclass in order to re-activate the breakpoints in SUT, once the execution stops in your testclass.
However, this solution does not work, if you are using the #Tested annotation in your testclass, because in this case the breakpoint in the testclass itself gets ignored.
Here is an example:
package de.playground;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import mockit.Expectations;
import mockit.Injectable;
import mockit.integration.junit4.JMockit;
#RunWith(JMockit.class)
public class DebuggingWithJMockitTest {
public interface Collaborator {
String execute(String... args);
}
public static class ToTest {
private Collaborator collaborator;
public ToTest(Collaborator collaborator) {
this.collaborator = collaborator;
}
public String doSomething() {
return collaborator.execute("a", "b");
}
}
#Injectable
private Collaborator collaborator;
#Tested
private ToTest toTest;
#Test
public void testHoldOnBreakpoint() {
new Expectations() {{
collaborator.execute((String[]) any); result = "whatever";
}};
String result = toTest.doSomething(); // add breakpoint here
assertThat(result, is("whatever"));
}
}
In this case the debugger does not stop in the String result = toTest.doSomething(); line. If you do not use the #Tested annotation and initialize the SUT in a #Beforemethod like this:
// #Tested is not used
private ToTest toTest;
#Before
public void before() {
toTest = new ToTest(collaborator);
}
the breakpoint works perfectly fine.
Is there any workaround how you can debug your code even if you are using the #Testedannotation in the test class?
This bug was brought up on the JMockit Google Group:
Yes, the problem is known, and already solved in JMockit 1.24.
It doesn't look like there was an issue logged for it. Our team ran into this issue on JMockit 1.23 and indeed was able to overcome it by upgrading to JMockit 1.24.
I'm developing custom runner of JUnit for internal purposes and, for instance, I've introduced custom annotation for test methods which on applying should make my runner to run method with this annotation after all other test methods without this annotation.
I want to write junit test to verify behavior of my custom runner.
Test class:
public class TestClass {
#Test
#CustomAnnotation
public void test1() {
System.out.println("test1");
}
#Test
public void test2() {
System.out.println("test2");
}
}
An abstract code that will test my runner:
public class MyCustomRunnerTest {
#Test
public void order() throws InitializationError {
// Arrange
// Some code of mocking library might be placed here
// Act
MyCustomRunner runner = new MyCustomRunner(TestClass.class);
runner.run(new RunNotifier());
// Assert
// Here I want to verify that method test1() has been called
// after method test2()
}
}
Is there any mocking libraries that will allow me to perform such verification? Or may be is there any other way to check that?
Why do you not extract the logic that determines the run order of test methods into a separate class or method? This method should return a list of test method names (or other descriptors) in order in which they will run. Then your testing will come down to passing it the test class and asserting that the output is { "test2", "test1" }. No mocking required.
A Better Solution
Use RunListener to log test methods as they are being run by your runner. You of course will have your own MyCustomRunner class, but the rest of the code can stay as in the example below:
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
#RunWith(BlockJUnit4ClassRunner.class)
public class RunnerTest {
// dummy "custom" test runner
public static class MyCustomRunner extends BlockJUnit4ClassRunner {
public MyCustomRunner(Class<?> klass) throws InitializationError {
super(klass);
}
}
public static class TestClass {
#Test
public void test1() {}
#Test
public void test2() {}
}
#Test
public void myCustomRunnerExecutesTestsInOrder() throws InitializationError {
RunNotifier notifier = new RunNotifier();
Collection<String> runTestMethods = new ArrayList<>();
notifier.addListener(new RunListener() {
#Override
public void testStarted(Description description) throws Exception {
runTestMethods.add(description.getMethodName());
}
});
new MyCustomRunner(TestClass.class).run(notifier);
// assert that the collection contains methods names in the specified order
assertThat(runTestMethods, contains("test1", "test2"));
}
}
I have the following testSuite
package com.swaserver.junit;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import junit.framework.TestSuite;
public class MyTestSuite extends TestSuite
{
#RunWith(Suite.class)
#SuiteClasses( { BinarySearchTest.class })
public class RunTestSuite
{
}
}
However, It tells me I have no runnable methods. My Unit test itself runs fine in my IDE using Junit4 annotations so there is defo a valid JUnit test contained in it.
However the Test Suite above complains about no Runnable Methods when run using the IDE and ANT
package com.swaserver.junit;
import org.junit.Test;
public class BinarySearchTest
{
#Test
public void test()
{
}
}
I was referencing this online example
http://selftechy.com/2011/04/16/junit-4-executing-multiple-test-cases
MyTestSuite should have the annotations defined at the class level, like so:
#RunWith(Suite.class)
#SuiteClasses( { BinarySearchTest.class })
public class MyTestSuite
{
}
If you're using the annotation based approach you shouldn't extend TestSuite, also you don't need the constructor.