Do JUnit test suites support custom annotations? - java

In JUnit, you can create test suites like so:
public class SecurityTest1 {
#Test
public void testSecurity1() {
// ...
}
}
public class LoadTest1 {
#Test
public void testLoad1() {
// ...
}
}
public class SecurityTest2 {
#Test
public void testSecurity2() {
// ...
}
}
#RunWith(Suite.class)
#SuiteClasses({SecurityTest1.class, SecurityTest2.class})
public class SecurityTestSuite {}
But this seems rather cumbersome. It would be so nice to define a simple class-level annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SecurityTest {}
And then define your suite like so:
#SecurityTest
public class SecurityTest1 {
#Test
public void testSecurity1() {
// ...
}
}
public class LoadTest1 {
#Test
public void testLoad1() {
// ...
}
}
#SecurityTest
public class SecurityTest2 {
#Test
public void testSecurity2() {
// ...
}
}
#RunWith(Suite.class)
#SuiteClasses({SecurityTest.class})
public class SecurityTestSuite {}
Is this possible? If so how? Note: not interested in switching to TestNG or any other test framework if JUnit does not support this...thanks in advance!

You can do it by implementing your own Test Runner similar to the Suite runner.
This runner should extract the marker annotation class from the value of the #SuiteClasses annotation (you should probably replace #SuiteClasses with your own annotation). Take a look at the getAnnotatedClasses method of the org.junit.runners.Suite class.
After having the marker annotation class, you should scan the classpath for test classes marked with this annotation (use a library such as Reflections) and pass an array of them to the appropriate Runner constructor.
You can find a similar behavior in the Suite constructor:
public Suite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
this(builder, klass, getAnnotatedClasses(klass));
}

Related

JUnit5: access extension field from test class

I need to use extensions to run code before and after all test cases in classes that use it. My test classes need to access a field in my Extension class. Is this possible?
Given:
#ExtendWith(MyExtension.class)
public class MyTestClass {
#Test
public void test() {
// get myField from extension and use it in the test
}
}
and
public class MyExtension implements
BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback {
private int myField;
public MyExtension() {
myField = someLogic();
}
...
}
How do I access myField from my test class?
You can achieve this via a marker annotation and a BeforeEachCallback extension.
Create a special marker annotation, e.g.
#Documented
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyField {
}
Use the annotation to find and set the values from within the extension:
import org.junit.jupiter.api.extension.BeforeEachCallback;
public class MyExtension implements BeforeEachCallback {
#Override
public void beforeEach(final ExtensionContext context) throws Exception {
// Get the list of test instances (instances of test classes)
final List<Object> testInstances =
context.getRequiredTestInstances().getAllInstances();
// Find all fields annotated with #MyField
// in all testInstances objects.
// You may use a utility library of your choice for this task.
// See for example, https://github.com/ronmamo/reflections
// I've omitted this boilerplate code here.
// Assign the annotated field's value via reflection.
// I've omitted this boilerplate code here.
}
}
Then, in your tests, you annotate the target field and extend the test with your extension:
#ExtendWith(MyExtension.class)
public class MyTestClass {
#MyField
int myField;
#Test
public void test() {
// use myField which has been assigned by the extension before test execution
}
}
Note: you can alternatively extend BeforeAllCallback which is executed once before all test methods of the class, depending on your actual requirements.

Autowiring is not working if test listener used in JUnit & Spring

I found, that uncommenting test listener annotation causes test not working below (autowired member is not initialized and NullPointerException occurs):
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestExecutionListenerTry2._Config.class)
//#TestExecutionListeners({TestExecutionListenerTry2._Listener.class})
public class TestExecutionListenerTry2 {
public static class Bean1 {
{
System.out.println("Bean1 constructor");
}
public void method() {
System.out.println("method()");
}
}
#Configuration
public static class _Config {
#Bean
public Bean1 bean1() {
return new Bean1();
}
}
public static class _Listener extends AbstractTestExecutionListener {
#Override
public void prepareTestInstance(TestContext testContext) throws Exception {
System.out.println("prepareTestInstance");
}
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
System.out.println("beforeTestClass");
}
}
#Autowired
public Bean1 bean1;
#Test
public void testMethod() {
bean1.method();
}
}
Why?
When you provide a #TestExecutionListeners annotation, you overwrite the default list of TestExecutionListener types, which includes a DependencyInjectionTestExecutionListener that handles dependency injection.
The default types are declared in the TestExecutionListener javadoc:
Spring provides the following out-of-the-box implementations (all of
which implement Ordered):
ServletTestExecutionListener
DependencyInjectionTestExecutionListener
DirtiesContextTestExecutionListener
TransactionalTestExecutionListener
SqlScriptsTestExecutionListener
Either register those as well. Or merge yours and the defaults with the technique outlined in the Spring documentation
To avoid having to be aware of and re-declare all default listeners,
the mergeMode attribute of #TestExecutionListeners can be set to
MergeMode.MERGE_WITH_DEFAULTS. MERGE_WITH_DEFAULTS indicates that
locally declared listeners should be merged with the default
listeners.
So your annotation would look like
#TestExecutionListeners(value = { TestExecutionListenerTry2._Listener.class },
mergeMode = MergeMode.MERGE_WITH_DEFAULTS)

PowerMock Mockito ignore junit FixMethodOrder

I have a little problem here, and I don't know how to solve it.
I have a class which have to make tests for some JSF beans.
In order to achieve that, I used PowerMock with Mockito for mocking the FacesContext, RequestContext and another static methods which are used inside the JSF beans.
#PrepareForTest(ClassWithStaticMethods.class)
#RunWith(PowerMockRunner.class)
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class MyTestingClass extends SomeTestBaseClass{
#BeforeClass
public static void init() throws Exception{
//mocking the FacesContext and others
}
#Test
public void test0001Create(){}
#Test
public void test0002Edit(){}
#Test
public void test0003Delete(){}
}
The SomeTestBaseClass, nothing complicated.
public abstract class SomeTestBaseClass {
#BeforeClass
public static void setUpBeforeClass() throws Exception {
//...
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
//...
}
}
The problem is that the order of tests is ignored (even with the FixMethodOrder annotation). If I remove PowerMockRunner (and the RunWith annotation), the order is kept but the mocking for static (and void) methods doesn't work.
But leaving the class with PowerMockRunner, the annotation #FixMethodOrder is ignored, totally.
I even tried with MockitoJUnitRunner, and here the order of tests is kept, but the mocking for static (and void) methods isn't done.
Does anyone have any idea why it is happening?
Thanks
I had the same problem getting them to run in the right order.
I solved it by using the #PowerMockRunnerDelegate annotation.
In my test class annotations:
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
#RunWith(PowerMockRunner.class)
I added #PowerMockRunnerDelegate(JUnit4.class):
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(JUnit4.class)
They now run in the expected order.
I believe this works because then it's not PowerMock that's running the tests, but JUnit 4 itself.
Like a workaround: Create a new method (let's say 'testAll'), put #Test annotation just for this (remove the #Test annotation from the rest of the methods), and then, call your testing methods inside of the annoted method.
Dirty, but it works.
#PrepareForTest(ClassWithStaticMethods.class)
#RunWith(PowerMockRunner.class)
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class MyTestingClass extends SomeTestBaseClass{
#BeforeClass
public static void init() throws Exception{
//mocking the FacesContext and others
}
#Test
public void testAll(){
this.test0001Create();
this.test0002Edit();
this.test0003Delete();
}
public void test0001Create(){}
public void test0002Edit(){}
public void test0003Delete(){}
}
Please try to change sequence:
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassWithStaticMethods.class)
I don't know why it doesn't work with the PowerMockRunner annotation but instead you could use a PowerMockRule
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class MyTestingClass extends SomeTestBaseClass {
#Rule
public PowerMockRule rule = new PowerMockRule();
#BeforeClass
public static void init() throws Exception {
// mocking the FacesContext and others
}
#Test
public void test0001Create() {
}
#Test
public void test0002Create() {
}
#Test
public void test0003Create() {
}
}

Test cases in inner classes with JUnit

I read about Structuring Unit Tests with having a test class per class and an inner class per method. Figured that seemed like a handy way to organize the tests, so I tried it in our Java project. However, the tests in the inner classes doesn't seem to be picked up at all.
I did it roughly like this:
public class DogTests
{
public class BarkTests
{
#Test
public void quietBark_IsAtLeastAudible() { }
#Test
public void loudBark_ScaresAveragePerson() { }
}
public class EatTests
{
#Test
public void normalFood_IsEaten() { }
#Test
public void badFood_ThrowsFit() { }
}
}
Does JUnit not support this, or am I just doing it wrong?
You should annontate your class with #RunWith(Enclosed.class), and like others said, declare the inner classes as static:
#RunWith(Enclosed.class)
public class DogTests
{
public static class BarkTests
{
#Test
public void quietBark_IsAtLeastAudible() { }
#Test
public void loudBark_ScaresAveragePerson() { }
}
public static class EatTests
{
#Test
public void normalFood_IsEaten() { }
#Test
public void badFood_ThrowsFit() { }
}
}
public class ServicesTest extends TestBase {
public static class TestLogon{
#Test
public void testLogonRequest() throws Exception {
//My Test Code
}
}
}
Making the inner class static works for me.
In JUnit 5, you simply mark non-static inner classes as #Nested:
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
public class DogTests {
#Nested
public class BarkTests {
#Test
public void quietBark_IsAtLeastAudible() { }
#Test
public void loudBark_ScaresAveragePerson() { }
}
#Nested
public class EatTests {
#Test
public void normalFood_IsEaten() { }
#Test
public void badFood_ThrowsFit() { }
}
}
I think some of the answers might be for older versions of JUnit. In JUnit 4 this worked for me:
#RunWith(Suite.class)
#Suite.SuiteClasses({ DogTests.BarkTests.class, DogTests.EatTests.class })
public class DogTests
{
public static class BarkTests
{
#Test
public void quietBark_IsAtLeastAudible() { }
#Test
public void loudBark_ScaresAveragePerson() { }
}
public static class EatTests
{
#Test
public void normalFood_IsEaten() { }
#Test
public void badFood_ThrowsFit() { }
}
}
I've had success with Nitor Creation's Nested Runner as well.
How to use Nitor Creation's Nested Runner
There is a post explaining it here:
Add this dependency:
<dependency>
<groupId>com.nitorcreations</groupId>
<artifactId>junit-runners</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
And a #RunWith to your test:
import com.nitorcreations.junit.runners.NestedRunner
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
#RunWith(NestedRunner.class)
public class RepositoryUserServiceTest {
public class RegisterNewUserAccount {
public class WhenUserUsesSocialSignIn {
public class WhenUserAccountIsFoundWithEmailAddress {
#Test
public void shouldThrowException() {
assertTrue(true);
}
}
}
}
}
PS: The example code has been taken and modified from the above blog post
I just ran across this posting (11 years later) regarding the testing of inner classes. An inner class can be trivially converted to equivalent static form only if the class should have been static in the first place. Static inner classes are not really inner classes because there is no enclosing this. They have exactly the same semantics (except for visibility restrictions) as top-level classes.
To test a "true" inner class [one that depends on its enclosing instance] you need to use the interface that the Java language provides for creating inner class instances outside the scope of the enclosing class. That interface includes an extra parameter in each constructor which is the enclosing instance. In this way, the Java compiler converts an inner class to a special top-level class with a mangled name (lots of $ signs) and augmented constructors. The same transformation can be performed at the source level. In principle, these transformed classes can be tested but it is a complex process because the tested program has transformed syntax and the test code must construct a (mock) object that serves as the enclosing instance.
Another way to test true inner classes is to write an executable method contract for each method consisting of an executable logical pre-condition and an executable logical post-condition. Then these executable contracts can be evaluated in the course of running a conventional top-level test that invokes the inner class methods.
In practice, I typically settle for the indirect testing of inner class methods in the course of top-level testing. Writing and testing executable contracts for all methods is a more rigorous, albeit significantly more expensive, alternative.

Annotation in Java Interface

Is there a way say,
import org.junit.Test;
public interface ITest {
#Test
public void runTest();
}
when I inherit this in a class it will automatically do this
public class Test implements ITest {
#Test
public void runTest() { }
}
instead of #Override?
By default annotations in Java are not inherited. If an annotation type has the meta-annotation #Inherited then it will be, but I don't think #Test does.

Categories