1

I want to have a custom JUnit annotation, and if that annotation is present on a test method, it should make the List of that object available to that test method, mostly through as a Method parameter.

Company is a outer class object which contains List<Employee> , and the test needs to have flexibility to have default employee list or providing a custom list.

For my test method, I am processing the annotation in respective test, however how can I have this annotation run for all the test files ( similar to @BeforeMethod) and if my custom annotation is present on a method, inject it as List<Employee>?

@Test
    @CompanyAnnotation(salary = 5)
    @CompanyAnnotation(salary = 50)
    public void testCompany(// Want to inject as method parameter of List<Employee> list) {

        for(Method method : CompanyTest.class.getDeclaredMethods()) {

                CompanyAnnotation[] annotations = method.getAnnotationsByType(
                        CompanyAnnotation.class);

                for(CompanyAnnotation d : annotations) {
                    System.out.println(b);
                }

        }

    }

===

class Company {
    // many other properties
    List<Employee> employeeList;

}

    class Employee {
       // more properties
      Integer age;
    }

    class CompanyBuilder {

    int defaultEmployeeSize = 10;

    public Company create(List<Employee> incoming) {
        List<Employee> employees = new ArrayList<>();

        employees.addAll(incoming);

        if ( employees.size() < defaultEmployeeSize )   {
            for(int i = 0; i < (defaultEmployeeSize - employees.size()); i++) {
                employee.add(new Employee());
            }
        }
        return employees;
    }
}
Novice User
  • 3,552
  • 6
  • 31
  • 56

2 Answers2

1

Here's a sketch of how you could tackle the problem:

  1. Create annotation CompanyAnnotation so that it has @ExtendWith(CompanyAnnotationProcessor) as a meta annotation. This will instruct Jupiter to use CompanyAnnotationProcessor as an extension for all test methods annotated with CompanyAnnotation. Moreover, CompanyAnnotation must be repeatable which requires something like a CompanyAnnotationList annotation.

  2. Implement CompanyAnnotationProcessor as ParameterResolver.

  3. Now you have to get at the original method annotations within CompanyAnnotationProcessor.resolveParameter. You do that by

    • first getting the method: Method method = (Method) parameterContext.getDeclaringExecutable();
    • then evaluate the methods annotations: org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations(method, CompanyAnnotation.class); BTW, AnnotationSupport requires to add junit-platform-commons to your dependencies.

Now you have all ingredients to create employees with the salary defined in the annotation.

johanneslink
  • 4,877
  • 1
  • 20
  • 37
0

You can have a BaseUnitTest class which will have as a @Before method, the annotation parsing. That way, it will apply to all existing unit tests. Note that this will slow the total execution time a bit.

How to get the executing test method - Get name of currently executing test in JUnit 4

Horatiu Jeflea
  • 7,256
  • 6
  • 38
  • 67
  • If I am understanding it correctly, you're saying the `BaseUnitTest` will be extended by all the existing test cases. That would be a huge project change. – Novice User Oct 01 '19 at 06:38
  • I was assuming it is a new project. If you are using Spring, you can achieve this using AOP (I will detail if it's feasible for you) or you can just use it on the particular classes you have that annotation on. – Horatiu Jeflea Oct 01 '19 at 06:41
  • Thanks! I'm not using spring. I was looking something about method proxies to dynamically inject as method parameter, if that is feasible. – Novice User Oct 01 '19 at 06:42
  • 1
    how about setting up a test suite and adding the annotation parsing logic there? https://stackoverflow.com/questions/82949/before-and-after-suite-execution-hook-in-junit-4-x and use wildcards https://stackoverflow.com/questions/7331214/junit4-run-all-tests-in-a-specific-package-using-a-testsuite/20613257 – Horatiu Jeflea Oct 01 '19 at 06:54
  • That sounds like a good approach! My problem seems pretty similar to how `@MethodSource` / `@ValueSource` works for JUnit in injecting a Stream of arguments. Though in my case, I want to inject a List of objects – Novice User Oct 01 '19 at 06:57
  • If you can use JUnit 5 annotations, use @ArgumentsSource, https://pasteboard.co/IzV7etV.png from https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/ just create your list of employees in a EmployeeArgumentProvider, wrap it in Arguments and convert it to stream – Horatiu Jeflea Oct 01 '19 at 07:11
  • That does not satisfy my purpose, because @ArgumentsSource generates a Stream of values, and for my use case its same List across all tests, not different among tests. – Novice User Oct 01 '19 at 17:01