如何使用 Arquillian 模拟 MyBatis 映射器接口(第 2 部分)?
How to mock MyBatis mapper interface with Arquillian (PART2)?
这是我第二次尝试使用 MyBatis 创建集成测试。我已经尝试了很多东西,但似乎没有解决这个问题的方法。希望大家能帮帮我。
In my previous question 我尝试编写一个集成测试来检查我的其余部分的输出 API。场景如下:rest API 调用注入的 EJB,它使用 MyBatis 执行一些 SQL:rest api > ejb > mybatis。不幸的是,我既不能注入,也不能模拟 MyBatis 映射器接口,所以我的测试不起作用:(
现在我创建了另一个测试场景,但我最终遇到了同样的情况。
现在我的场景非常简单:我有一个带有注入 MyBatis 映射器的 EJB。我想在带有 Arquillian 的嵌入式 Glassfish/Payara 服务器中测试它。
这是我的例外:
org.glassfish.deployment.common.DeploymentException: CDI deployment failure:WELD-001408: Unsatisfied dependencies for type AccountDao with qualifiers @Default
at injection point [BackedAnnotatedField] @Inject private a.b.c.AppleBean.accountDao
at a.b.c.AppleBean.accountDao(AppleBean.java:0)
EJB:
@Stateless
public class AppleBean {
@Inject
private AccountDao accountDao;
public String say() {
return "Apple";
}
}
账户映射器 (DAO):
@Mapper
public interface AccountDao {
@Select("SELECT * FROM account WHERE id = #{id}")
@Results({
@Result(property = "email", column = "email", javaType = String.class),
@Result(property = "firstName", column = "first_name", javaType = String.class),
@Result(property = "lastName", column = "last_name", javaType = String.class),
})
Account findById(@Param("id") Long id);
}
我的测试class:
@RunWith(Arquillian.class)
public class AppleBeanTest {
@EJB
private AppleBean bean;
@Deployment
public static WebArchive createDeployment() {
return ShrinkWrap
.createFromZipFile(WebArchive.class, new File("target/war-demo-test-1.0.war"))
.addPackages(true, "a.b");
}
@Test
public void say() throws Exception {
assertNotNull(bean);
System.out.println(bean.say());
}
}
如果我评论 AppleBeanTest
中的两行以删除对 MyBatis 映射器的引用,那么我的测试工作正常。
I uploaded the source code to github as well.
解决方案
我的测试中缺少以下 class。 @blackwizard 谢谢你指引我正确的方向。
SessionFactoryProducer.java
@ApplicationScoped
public class SessionFactoryProducer {
@ApplicationScoped
@Produces
@SessionFactoryProvider
public SqlSessionFactory produce() throws Exception {
SqlSessionFactory sessionFactory;
try (Reader reader = Resources.getResourceAsReader("mybatis.xml")) {
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
// create sample table
//createTable(sessionFactory);
return sessionFactory;
}
private void createTable(final SqlSessionFactory manager) throws Exception {
try (SqlSession session = manager.openSession()) {
LOGGER.info("-> Initializing database...");
Connection conn = session.getConnection();
Reader reader = Resources.getResourceAsReader("create-table-postgresql.sql");
ScriptRunner runner = new ScriptRunner(conn);
runner.runScript(reader);
reader.close();
LOGGER.info("=> Database has been initialized properly.");
} catch (Exception ex) {
LOGGER.error("Error executing SQL Script...", ex);
}
}
}
git 项目已更新。
现在,我没有资源可以克隆,运行 你的项目来确认我要说的话。但如果有必要的话我会在周一,同时,以下可能是一个轨道:
我认为它不起作用,因为缺少一些非常重要的东西:SqlSessionFactory
。
mybatis-cdi doc 在第一段中指出:
The SqlSessionFactory is the source of any MyBatis bean so first you
need to create one (at least) and let the container know about it
existence.
的确,没有Session就没有理由获取Mapper实例。如果 @Mapper
注释就足够了,它只能提供一个空的 shell 因为没有 link 给任何底层数据源。
那么如果没有Mapper,就不能注入到EJB中,这就是Weld所抱怨的。
部署成功后,是否与@Inject private AccountDao accountDao
?我不明白为什么 Weld 会允许不注入任何东西。但如果是,请检查 accountDao
值(调试断点或日志)。
这是我第二次尝试使用 MyBatis 创建集成测试。我已经尝试了很多东西,但似乎没有解决这个问题的方法。希望大家能帮帮我。
In my previous question 我尝试编写一个集成测试来检查我的其余部分的输出 API。场景如下:rest API 调用注入的 EJB,它使用 MyBatis 执行一些 SQL:rest api > ejb > mybatis。不幸的是,我既不能注入,也不能模拟 MyBatis 映射器接口,所以我的测试不起作用:(
现在我创建了另一个测试场景,但我最终遇到了同样的情况。 现在我的场景非常简单:我有一个带有注入 MyBatis 映射器的 EJB。我想在带有 Arquillian 的嵌入式 Glassfish/Payara 服务器中测试它。
这是我的例外:
org.glassfish.deployment.common.DeploymentException: CDI deployment failure:WELD-001408: Unsatisfied dependencies for type AccountDao with qualifiers @Default
at injection point [BackedAnnotatedField] @Inject private a.b.c.AppleBean.accountDao
at a.b.c.AppleBean.accountDao(AppleBean.java:0)
EJB:
@Stateless
public class AppleBean {
@Inject
private AccountDao accountDao;
public String say() {
return "Apple";
}
}
账户映射器 (DAO):
@Mapper
public interface AccountDao {
@Select("SELECT * FROM account WHERE id = #{id}")
@Results({
@Result(property = "email", column = "email", javaType = String.class),
@Result(property = "firstName", column = "first_name", javaType = String.class),
@Result(property = "lastName", column = "last_name", javaType = String.class),
})
Account findById(@Param("id") Long id);
}
我的测试class:
@RunWith(Arquillian.class)
public class AppleBeanTest {
@EJB
private AppleBean bean;
@Deployment
public static WebArchive createDeployment() {
return ShrinkWrap
.createFromZipFile(WebArchive.class, new File("target/war-demo-test-1.0.war"))
.addPackages(true, "a.b");
}
@Test
public void say() throws Exception {
assertNotNull(bean);
System.out.println(bean.say());
}
}
如果我评论 AppleBeanTest
中的两行以删除对 MyBatis 映射器的引用,那么我的测试工作正常。
I uploaded the source code to github as well.
解决方案
我的测试中缺少以下 class。 @blackwizard 谢谢你指引我正确的方向。
SessionFactoryProducer.java
@ApplicationScoped
public class SessionFactoryProducer {
@ApplicationScoped
@Produces
@SessionFactoryProvider
public SqlSessionFactory produce() throws Exception {
SqlSessionFactory sessionFactory;
try (Reader reader = Resources.getResourceAsReader("mybatis.xml")) {
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
// create sample table
//createTable(sessionFactory);
return sessionFactory;
}
private void createTable(final SqlSessionFactory manager) throws Exception {
try (SqlSession session = manager.openSession()) {
LOGGER.info("-> Initializing database...");
Connection conn = session.getConnection();
Reader reader = Resources.getResourceAsReader("create-table-postgresql.sql");
ScriptRunner runner = new ScriptRunner(conn);
runner.runScript(reader);
reader.close();
LOGGER.info("=> Database has been initialized properly.");
} catch (Exception ex) {
LOGGER.error("Error executing SQL Script...", ex);
}
}
}
git 项目已更新。
现在,我没有资源可以克隆,运行 你的项目来确认我要说的话。但如果有必要的话我会在周一,同时,以下可能是一个轨道:
我认为它不起作用,因为缺少一些非常重要的东西:SqlSessionFactory
。
mybatis-cdi doc 在第一段中指出:
The SqlSessionFactory is the source of any MyBatis bean so first you need to create one (at least) and let the container know about it existence.
的确,没有Session就没有理由获取Mapper实例。如果 @Mapper
注释就足够了,它只能提供一个空的 shell 因为没有 link 给任何底层数据源。
那么如果没有Mapper,就不能注入到EJB中,这就是Weld所抱怨的。
部署成功后,是否与@Inject private AccountDao accountDao
?我不明白为什么 Weld 会允许不注入任何东西。但如果是,请检查 accountDao
值(调试断点或日志)。