arquillian-core icon indicating copy to clipboard operation
arquillian-core copied to clipboard

NullPointerException when interceptBeforeEach in @Nested class invoke method that has fields with @EJB or @Inject annotation

Open rimuln opened this issue 3 years ago • 1 comments

Bug report / Enhancement

Issue Overview

NPE is fired before @Test method is executed in @Nested class.

Expected Behaviour

NPE isn't throw and @Test runs successfuly

Steps To Reproduce
@ExtendWith(ArquillianExtension.class)
@ArquillianSuiteDeployment
@Transactional(TransactionMode.ROLLBACK)
public abstract class ArquillianBasedTest {
  private static final Logger LOG = LogManager.getLogger();

  @EJB
  private ServerStateService serverStateService;

  @Inject
  private IAppServerPathProvider appServerPathProvider;

  @BeforeEach
  protected void setUp() throws Exception {
    waitForServer();
  }

  private void waitForServer() throws Exception {
    org.awaitility.Awaitility.await().until(() -> ServerState.READY.equals(serverStateService.getServerState())); //here occured NPE as serverStateService is null
  }
}
class TypeLevelReferenceDaoIntegrationTest  extends ArquillianBasedTest {

  @EJB
  private ITypeLevelReferenceDao daoUnderTest;

 @Test
  void testFindTypeLevelReferenceByTypeElementPathViaReferenceTypeElement() {
//tests that are directly in class runs fine. All EJB, CDI fields are injected
  }

 @Nested
  class NestedTest {

    @Test
    void testx() {
      System.out.println("Hello world from nested test "); //this line is never invoked as first it run @BeforeEach and failed on NPE
    }
}

When debug it:

  • when it is "parent" test method then in org.jboss.arquillian.junit5.container.JUnitJupiterTestRunner.execute(Class<?>, String) testClass is TypeLevelReferenceDaoIntegrationTest
  • org.jboss.arquillian.junit5.ArquillianExtension.interceptBeforeEachMethod(Invocation<Void>, ReflectiveInvocationContext<Method>, ExtensionContext)
  • invocation delegate target is instance of testClass and has all fields correctly injected
  • when it is nested case then testClass is TypeLevelReferenceDaoIntegrationTest$NestedTest
  • invocation delegate target is integration.de.ids.acos.et.server.dao.ooe.type.TypeLevelReferenceDaoIntegrationTest@3d91b4a1 and all fields are null

the condition predicate says that it runs insideArquillian

TestMethodTestDescriptor: [engine:junit-jupiter]/[class:integration.de.ids.acos.et.server.dao.ooe.type.TypeLevelReferenceDaoIntegrationTest]/[nested-class:NestedTest]/[method:testx()]

testInstances are: [integration.de.ids.acos.et.server.dao.ooe.type.TypeLevelReferenceDaoIntegrationTest@3d91b4a1, integration.de.ids.acos.et.server.dao.ooe.type.TypeLevelReferenceDaoIntegrationTest$NestedTest@5dcbafbe]

rimuln avatar Apr 13 '21 16:04 rimuln

I am also having this same issue. However it seems like it's not necessarily an issue with @BeforeEach but an issue with injected fields not being injected within the context of running tests within a @Nested class.

@ExtendWith(ArquillianExtension.class)
public class FooTest {
    @Inject
    private Foo foo;
    
    @BeforeEach
    public setUp(){
        //foo will be set if running against outerTest() but will be null if running for nestedTest()
    }
    
    @Test
    public outerTest(){
        assertThat(foo, is(notNullValue()); //This is fine
    }
    
    @Nested
    public class NestedFooTest(){
        @Test
        public nestedTest(){
            assertThat(foo, is(notNullValue()); //foo will be null
        }
    }
}

The above example is stripped down do highlight where Injection seems to work but my actual code looks very like the original example with an abstract arqullian test class annotated with @ArquillianSuiteDeployment in case that is making a difference.

allan-t avatar Apr 27 '22 11:04 allan-t