简体   繁体   中英

How to mock MyBatis mapper interface with Arquillian (PART2)?

This is my 2nd try to create integration test with MyBatis. I have tried many things but it seems that there is no solution for this issue. Hope that you guys can help me.

In my previous question I tried to write an integration test to check the output of my rest API. The scenario there was the following: rest API calls an injected EJB which executes some SQL with MyBatis: rest api > ejb > mybatis. Unfortunately I was not able neither to inject, nor mock MyBatis mapper interface so my test does not work :(

Now I created another test scenario but I ended up in a same situation. Now my scenario is crazy easy: I have an EJB with an injected MyBatis mapper. I would like to test it within an embedded Glassfish/Payara server with Arquillian.

This is my exception:

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

Account maper (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);
}

My test 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());
    }
}

If I comment the two lines in AppleBeanTest to remove the refelence to MyBatis mapper then my test works fine.

I uploaded the source code to github as well.


SOLUTION

The following class was missing from my test. @blackwizard thank you for putting me to the right direction.

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

The git project is updated.

Here and now, I have not resources to clone and run your project to confirm what I will say. But I will on Monday if necessary and in the meantime, the following may be a track:

I think it does not work because something very important is missing: the SqlSessionFactory .

mybatis-cdi doc states in the first paragraph:

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.

Indeed, there is no reason to obtain a Mapper instance if there is no Session. if @Mapper annotation was sufficient, it could only provide an empty shell because not link to any underlying datasource. Then if there is no Mapper, it cannot be injected into the EJB, that's what Weld complains about.

When deployment succeeds, is it with the @Inject private AccountDao accountDao ? I don't see why Weld would allow injecting with nothing. But if it does, check accountDao value (debug break point or log).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM