在 Java SE 上运行单元测试时使用带有 Weld 的 CDI 不满意的依赖项

问题描述

我有一个小型(Java SE 11.x)项目,我正在使用 Weld 测试 CDI。我有这些依赖项(除其他外,但这些是与此问题相关的依赖项):

implementation("org.jboss.weld.se:weld-se-core:4.0.0.Final")

runtimeOnly("javax:javaee-api:8.0.1")

testImplementation("org.jboss.weld:weld-junit5:2.0.2.Final")

然后我有一个简单的实体类

@Entity
@Table(name = "spell_books")
public final class SpellBook extends AbstractPersistable {
  @Id
  @GeneratedValue(generator = "uuid2")
  @GenericGenerator(name = "uuid2",strategy = "uuid2")
  @Column(name = "id",nullable = false,updatable = false)
  private UUID id;

  @Column(name = "name")
  private String name;

  // ...some one-to-many and many-to-may relationships

  public SpellBook() { // No-args constructor required by JPA
    spells = new LinkedList<>();
    wizards = new LinkedList<>();
  }

  public SpellBook(final String name) {
    this();
    this.name = name;
  }

  public void add(final Spell spell) {
    spell.setSpellBook(this);
    spells.add(spell);
  }
}

@MappedSuperclass
public abstract class AbstractPersistable implements Serializable {
  @Version
  @Column(name = "version")
  private Long version;
}

...和一个数据库交互的 DAO 类:

import jakarta.inject.Singleton;
import lombok.extern.log4j.Log4j2;

@Log4j2
@Singleton
public class SpellBookDao extends AbstractJpaDao<SpellBook> {
  public Optional<SpellBook> findByName(final String name) {
    logger.debug("Searching spell book with name [{}]...",name);
    final var builder = entityManager.getCriteriaBuilder();
    final var criteria = builder.createquery(clazz);
    final var model = criteria.from(clazz);
    criteria.select(model).where(builder.equal(model.get("name"),name));
    return Optional.ofNullable(entityManager.createquery(criteria.select(model)).getSingleResult());
  }
}

@Log4j2
public abstract class AbstractJpaDao<T extends AbstractPersistable> {
  @PersistenceContext
  protected EntityManager entityManager;

  protected Class<T> clazz;

  public void setClazz(final Class<T> clazz) {
    this.clazz = clazz;
  }

  // ...some defaults for persist,merge,findAll,findOne,etc.
}

我想做的是为 DAO 类编写一个简单的单元测试:

import jakarta.inject.Inject;
import org.acme.service_layer.persistence.SpellBookDao;
import org.assertj.core.api.Assertions;
import org.jboss.weld.junit5.EnableWeld;
import org.junit.jupiter.api.disabled;
import org.junit.jupiter.api.Test;

import java.util.UUID;

@EnableWeld
final class SpellBookDaoTest {
  @Inject
  private SpellBookDao dao;

  @Test
  void findByName_WhenSpellBookExists() {
    final var optional = dao.findByName("The Dark Lord Ascending");
    Assertions.assertthat(optional)
        .hasValueSatisfying(it -> {
          Assertions.assertthat(it.getId()).isEqualTo(UUID.fromString("715811c9-ae11-41ec-8652-671fd88cd2a0"));
          Assertions.assertthat(it.getName()).isEqualTo("The Dark Lord Ascending");
          Assertions.assertthat(it.getSpells()).isEmpty();
          Assertions.assertthat(it.getWizards()).isEmpty();
          // ...
          Assertions.assertthat(it.getVersion()).isEqualTo(0L);
        });
  }
}

此堆栈跟踪总是失败:

WELD-001408: Unsatisfied dependencies for type SpellBookDao with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private org.acme.service_layer.persistence.internal.SpellBookDaoTest.dao
  at org.acme.service_layer.persistence.internal.SpellBookDaoTest.dao(SpellBookDaoTest.java:0)

org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type SpellBookDao with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private org.acme.service_layer.persistence.internal.SpellBookDaoTest.dao
  at org.acme.service_layer.persistence.internal.SpellBookDaoTest.dao(SpellBookDaoTest.java:0)

    at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:378)

...many more here

我已经搜索了很多类似的问题/答案,但仍然无法弄清楚我在这里做错了什么。有什么建议吗?

顺便说一下,我确实有 main/resources/meta-inf/beans.xmltest/resources/meta-inf/beans.xml。两者的内容相同:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
    bean-discovery-mode="all">
  <scan>
    <exclude name="org.jboss.weld.**" />
  </scan>
</beans>

解决方法

正如我在此问题的 GitHub issue 中所述 - 这是一个问题,因为截至今天 (23/02/2021),weld-junit 版本 2.x 已设置为使用 Java /Jakarta EE 8。我需要为 Jakarta EE 9 及其 jakarta 命名空间发布一个新的主要版本,该命名空间由 Weld 4 实现。应该不会太难,我希望能够找到时间在一两周内完成。

编辑:weld-junit 版本 3.0.0.Final 现在在 Central 中可用,旨在与 Jakarta EE 9 命名空间一起使用,因此应有效解决上述问题。

在那之前,您只能使用 weld-junit,前提是您切换到具有 javax 命名空间的 EE 8,并且还使用实现该名称的 Weld 3。

最后但并非最不重要的一点是,您的项目混淆了 EE 8 和 EE 9 工件 - 这是您需要解决的问题,主要是由于两者之间的命名空间差异,并且即使在我们修复后仍会继续导致问题weld-junit

,

我认为如果您没有使用范围注释至少注释一个,CDI 无法提供实现。 将@ApplicationScoped 或@Singleton 放在 SpellBookDao 上

刚刚看到您已经设置了应该可以工作的 bean-discovery-mode="all"...

[编辑]

Add to your gradle
test.doFirst {
    copy {
        from 'build/resources/main/META-INF/beans.xml'
        into 'build/classes/main/META-INF/'
    }
    copy {
        from 'build/resources/test/META-INF/beans.xml'
        into 'build/classes/test/META-INF/'
    }
}

来自https://stackoverflow.com/a/20355024/2710704

,

更改您的测试:

@ExtendWith(WeldJunit5Extension.class)
final class SpellBookDaoTest {

  @WeldSetup
  WeldInitiator weldInitiator =  WeldInitiator.of(SpellBookDao.class);

在 grade 配置中添加对 API 的依赖: ` testImplementation("javax:javaee-api:8.0.1") ``

然后就会找到你的 bean。 您现在必须提供 EntityManager。

文档在这里 https://github.com/weld/weld-junit/blob/master/junit5/README.md https://weld.cdi-spec.org/news/2017/12/19/weld-meets-junit5/

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...