在Mockito中替换DataSource

时间:2012-03-15 00:10:18

标签: java junit mocking jndi mockito

我有在Jboss服务器上执行查询的代码。它有基于JNDI的数据源,如下所示:

    public class JNDIBasedDao {

        DataSource dataSource;

        public JNDIBasedDao(){

            try {
                InitialContext ic = new InitialContext();
                dataSource = (DataSource) ic.lookup("java://bla-bla-bla");
            } catch (NamingException e) {
            e.printStackTrace();
            }


        }

public class Manager {

    public Manager(){}

    private JNDIBasedDao dao = new JNDIBasedDao();

    public void runOperation(){
        this.dao.executeInsert();
    }

在我的笔记本电脑上,我没有Jboss,也没有能力连接到这台服务器,并希望在HSQLDB上运行单元测试。

我想基于HSQLDB从apache commons创建BasicDataSource并将此对象注入JNDIBasedDao。

@Mock
BasicDataSource dataSource = new BasicDataSource();

@Mock 
JNDIBasedDao dao = new JNDIBasedDao();

@InjectMocks
Manager manager = new Manager();
@Before
    public void initMocks(){
        dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
        dataSource.setUrl("jdbc:hsqldb:mem:dannyTest");
        dataSource.setUsername("sa");
        dataSource.setPassword("");
        dataSource.setInitialSize(5);
        dataSource.setMaxActive(10);
        dataSource.setPoolPreparedStatements(true);
        dataSource.setMaxOpenPreparedStatements(10);

        MockitoAnnotations.initMocks(this);

    }

    @Test
    public void testRunOperartion() {
        manager.runOperartion();
    }

但我仍然收到JNDI错误。可以吗?请帮忙。

3 个答案:

答案 0 :(得分:1)

@InjectMocks只会进行二次注射。

在Manager类中更改以下内容

private JNDIBasedDao dao = new JNDIBasedDao();

private JNDIBasedDao dao;

并添加

void setDao(JNDOBasedDao dao)
{
   this.dao = dao;
}

答案 1 :(得分:1)

您可以创建第二个构造函数并注入InitialContext。

public class JNDIBasedDao {
  DataSource dataSource;

  public JNDIBasedDao() {
    this(new InitialContext());
  }

  public JNDIBasedDao(InitialContext ic) {
    try {
      dataSource = (DataSource) ic.lookup("java://bla-bla-bla");
    } catch (NamingException e) {
      e.printStackTrace();
    }
  }

  ....
}

现在,您可以提供一个模拟的InitialContext,它提供了您的DataSource。

答案 2 :(得分:1)

由于您正在使用@Mock,因此无需通过调用其构造函数来实际实例化这些对象。

而不是:

@Mock
BasicDataSource dataSource = new BasicDataSource();

@Mock 
JNDIBasedDao dao = new JNDIBasedDao();

尝试:

@Mock
BasicDataSource dataSource;

@Mock 
JNDIBasedDao dao;

让Mockito处理创建这些类的模拟版本。

当然,当你这样做时,你得到这些类的模拟版本,所以在你的dataSource上调用所有这些方法会导致调用默认的Mockito stubbings ......它什么也不做。

不确定为什么你将@Mock与方法调用合并在一个看起来像你希望得到结果的同一个对象上......

也许单步执行调试器并检查在抛出异常时使用的对象的运行时类。它们可能不是你所期望的那样。