【问题标题】:Arquillian testing JSF with CDI - CDI Scope issueArquillian 使用 CDI 测试 JSF - CDI 范围问题
【发布时间】:2017-06-13 02:25:17
【问题描述】:

我们正在将我们的 JavaEE 应用程序从 Weblogic 10.3.6 迁移到 Weblogic 12.2.1.2。作为此迁移的一部分,我们正在更改 JSF 托管 bean 以使用 CDI 注释而不是标准 JSF 注释。 @ManagedBean@Namedjavax.faces.bean.ViewScopedjavax.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>

BackingBean:

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";
    }
}

TestBean

@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]

【问题讨论】:

    标签: jsf jakarta-ee cdi jsf-2.2 jboss-arquillian


    【解决方案1】:

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

    Bean 实例本身是在测试中创建的,然后通过使用反射将所有依赖项插入其中。这适用于 bean、entitymanger 等

    @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);
    }
    }
    

    TestHelper 看起来像这样

    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);
    }
    }
    

    【讨论】:

      【解决方案2】:

      最后我不得不用一个很好的老式 hack 来解决这个问题。我找到了org.apache.webbeans.container.BeanManagerImpl 的来源,原来的WebBeans context with scope type annotation @ViewScoped does not exist within current thread 来自哪里。我在我的测试源中创建了这个类,然后我做了一些改变来解决这个问题。

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

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

      【讨论】:

        猜你喜欢
        • 2015-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-17
        • 2012-08-03
        • 2012-01-20
        相关资源
        最近更新 更多