CdiUnit test with Junit @Rule is impossible because of a public private field paradox
Asked Answered
C

1

7

The following snippet is enough to reproduce my problem:

  • Either I set the thrown attribute public and get the error org.jboss.weld.exceptions.DefinitionException: WELD-000075: Normal scoped managed bean implementation class has a public field
  • Or I remove the public modifier and get the error org.junit.internal.runners.rules.ValidationError: The @Rule 'thrown' must be public.
  • I also tried to let the public modifier in place and to add the @Dependent annotation scope on the class, but got error org.jboss.weld.exceptions.DefinitionException: WELD-000046: At most one scope may be specified on [EnhancedAnnotatedTypeImpl] public @Dependent @ApplicationScoped @RunWith

I stripped out all unnecessary code, but this is quite a complex unit test with mock, service injection through CDI and some test methods thar are expected to throw an exception.

import org.jglue.cdiunit.CdiRunner;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;

@RunWith(CdiRunner.class)
public class FooBarTest {

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void test() {

    }
}

So my problem is that on one hand Weld wants all fields to not be public because it will not be able to proxify the class otherwise, and on the other hand, JUnit want Rule fields to be public because it is using reflection to access them and does not want to use the setAccessible(true) method because of the cases where the security manager is active. How to deal with that paradox?

NB: I also found a hint comments to this answer, stating that

You can also annotate a method with @Rule, so this would avoid the problem

But I could not found any example of junit test with a @Rule annotation on a method, I plan to ask a separate question about this.

Chirp answered 21/10, 2016 at 11:50 Comment(0)
C
16

I found out how to solve the problem. For future reference, here is a snippet that works, hope this will help other people.

import org.jglue.cdiunit.CdiRunner;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;


@RunWith(CdiRunner.class)
public class FooBarTest {

    private ExpectedException thrown = ExpectedException.none();

    @Rule
    public ExpectedException getThrown() {
        return thrown;
    }

    @Test
    public void test() {
        thrown.expect(ArithmeticException.class);
        int i = 1 / 0;
    }
}
Chirp answered 21/10, 2016 at 12:24 Comment(2)
Very nice. I would recommend raising an enhancement with CdiUnit team, they shouldn't necessarily make tests @ApplicationScoped.Bespectacled
Nice idea but only works partly. You cannot use a rule to provide things for the test using @Produces because CDI producers are called before Rules are applied. :(Tinge

© 2022 - 2024 — McMap. All rights reserved.