Arquillian测试JSF与CDI - CDI范围问题



我们正在将JavaEE应用程序从Weblogic 10.3.6迁移到Weblogic 12.2.1.2。 作为此迁移的一部分,我们将 JSF 管理的 bean更改为使用 CDI 注释而不是标准 JSF 注释。 @ManagedBean @Namedjavax.faces.bean.ViewScoped javax.faces.view.ViewScoped。 事实证明,这只是一些小问题。 但是,我在尝试运行我们的测试时遇到了一个大问题。测试失败,并显示以下错误:

WebBeans context with scope type annotation @ViewScoped does not exist within current thread

我已经尝试了多个不同的容器(嵌入式和远程),但仍然收到相同的错误。 任何帮助将不胜感激。

我正在使用具有以下pom.xml依赖项的Arquillian:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.arquillian</groupId>
            <artifactId>arquillian-bom</artifactId>
            <version>1.1.12.Final</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>arquillian-openejb-embedded</artifactId>
        <version>7.0.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.jboss.arquillian.junit</groupId>
        <artifactId>arquillian-junit-container</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>javax.faces</groupId>
        <artifactId>javax.faces-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.primefaces</groupId>
        <artifactId>primefaces</artifactId>
        <version>6.0.13</version>
    </dependency>
    <dependency>
        <groupId>org.primefaces.themes</groupId>
        <artifactId>all-themes</artifactId>
        <version>1.0.10</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

背豆:

import javax.faces.view.ViewScoped;
import javax.inject.Named;
import java.io.Serializable;
@Named
@ViewScoped
public class AnotherBean implements Serializable {
    public String doTest()
    {
        System.out.println("test");
        return "test";
    }
}

测试豆

@RunWith(Arquillian.class)
public class TestAgain  {
    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class, "test.jar")
                .addClass(AnotherBean.class)
                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }
    @Inject
    AnotherBean anotherBean;
    @Test
    public void doTest()
    {
        Assert.assertEquals(anotherBean.doTest(), "test");
        anotherBean.doTest();
    }
}

更新

如果我将@Deployment更改为:

@Deployment
    public static WebArchive createDeployment() {
        return ShrinkWrap.create(WebArchive.class, "test.jar")
                .addClass(AnotherBean.class)
                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }

我得到:

javax.enterprise.inject.UnsatisfiedResolutionException: Api type [AnotherBean] is not found with the qualifiers 
Qualifiers: [@javax.enterprise.inject.Default()]
for injection into Field Injection Point, field name :  anotherBean, Bean Owner : [null]

我们在测试@ViewScoped豆时也会遇到类似的困难。我们通过自己在测试中创建带有注入的豆子来解决这个问题。

Bean 实例本身是在测试中创建的,然后使用反射将所有依赖项插入其中。这适用于豆类、实体经理等

@RunWith(Arquillian.class)
public class ViewControllerTest {
@Inject private OtherBean otherBean;
private ViewController viewController;

@Deployment
public static WebArchive createDeployment() {
  return WebArchiveFactory.getDefaultWebarchArchive();
}
@Before
public void setup() throws Exception {
  viewController = new ViewController();
  TestHelper.setFacesContext(); // provide FacesContextMock
  TestHelper.inject(viewController, "otherBean", otherBean);
}
}

测试助手看起来像这样

public class TestHelper {
public static void inject(Object bean, 
                          String fieldName, 
                          Object fieldValue) throws Exception {
  if (null == bean) {
    throw new IllegalArgumentException("Bean must not be null");
  }
  Field field;
  try {
    field = bean.getClass().getDeclaredField(fieldName);
  } catch (NoSuchFieldException e) {
    log.log(Level.SEVERE, "Could not find field for injection: " + fieldName);
    throw e;
  }
  field.setAccessible(true);
  field.set(bean, fieldValue);
}
}
最后,

我不得不用一个老式的黑客来解决这个问题。 我找到了原始WebBeans context with scope type annotation @ViewScoped does not exist within current thread的来源org.apache.webbeans.container.BeanManagerImpl。 我在测试源中创建了这个类,然后进行了一些更改来解决这个问题。

最终,对于我的测试,我不关心范围。 我正在测试方法是否运行并返回正确的逻辑/数据。 因此,在类中,它会检查 bean 所处的作用域类型并抛出异常。 我只是检查了它是否在Viewscoped中,如果是,请将其更改为Dependent. 然后,这使我的测试得以工作。

不是最好的解决方案,但它有效。

最新更新