java 使用 Mockito 1.9.5 模拟 JdbcTemplate.queryForObject(..,...,...,)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/40257093/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mocking JdbcTemplate.queryForObject(..,...,...,) with Mockito 1.9.5
提问by Sabir Khan
My question is similar to this SO question
我的问题类似于this SO question
I have two JdbcTemplate.queryForObject(..,...,...,)calls in service like below, 
我有两个JdbcTemplate.queryForObject(..,...,...,)服务电话,如下所示,
depositPostedAmt = jdbcTemplate.queryForObject(Constants.FETCH_DEPOSIT_POSTED_AMT, BigDecimal.class,new Object[] { remitBean.getDepositId() });
and
和
claimPostedAmt =jdbcTemplate.queryForObject(Constants.FETCH_CLAIM_POSTED_AMOUNT,BigDecimal.class, new Object[] { claim.getClaimId(), remitBean.getContractNum() });
Third argument, new Object[]is different among those two calls and actual sql String differs. 
So I am trying to use to different mockings to return two different objects in both scenario as shown below , 
第三个参数,new Object[]在这两个调用之间是不同的,实际的 sql String 不同。所以我试图使用不同的模拟来在两种场景中返回两个不同的对象,如下所示,
when(jdbcTemplate.queryForObject(eq(Constants.FETCH_DEPOSIT_POSTED_AMT), eq(BigDecimal.class), anyObject())).thenReturn(depositPostedAmt);
when(jdbcTemplate.queryForObject(eq(Constants.FETCH_CLAIM_POSTED_AMOUNT), eq(BigDecimal.class), anyObject())).thenReturn(claimPostedAmt);
i.e. I wish to receive two different BigDecimalon two different queries. 
即我希望BigDecimal在两个不同的查询中收到两个不同的信息。
I receive depositPostedAmtas expected but claimPostedAmtis always null even though I have initialized it in @Before method same as depositPostedAmtso I am guessing that my whenmatcher doesn't found any match. I have tried various syntax for third argument matching like any(Object[].class)and anyRef(objectArray)etc but second time, I always get NULL. 
我depositPostedAmt按预期收到但claimPostedAmt始终为空,即使我已经在 @Before 方法中初始化它,depositPostedAmt所以我猜我的when匹配器没有找到任何匹配项。我已经尝试了第三个参数匹配,例如不同的语法any(Object[].class)和anyRef(objectArray)等,但第二次,我总是NULL。
I am not sure as what I am missing as there are no errors. I am using JUnit along with Mockito 1.9.5.
我不确定我缺少什么,因为没有错误。我正在使用 JUnit 和 Mockito 1.9.5。
Here is sample code - everything works OK except that claimPostedAmtremains null in called service. 
这是示例代码 - 一切正常,除了claimPostedAmt在被调用的服务中保持为空。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class, loader = AnnotationConfigContextLoader.class)
public class RCMatchDaoImplTest{
    @Autowired private RCMatchDaoImpl  service;
    @Autowired private JdbcTemplate jdbcTemplate;
    @Autowired private Logger logger;
    private RemitBean remitBean;
    private List<RemitBean> remitBeanList;
    private BigDecimal depositPostedAmt,claimPostedAmt,remitAmount;
    private ClaimVO claim;
    private List<ClaimVO> claims;
    @Before
    public void setUp() throws NoSuchFieldException, SecurityException, Exception{
        /* Set dependencies*/
        service.setJdbcTemplate(jdbcTemplate);
        setFinalStatic(RCMatchDaoImpl.class.getDeclaredField("logger"),logger);
        remitBean = new RemitBean();
        remitBeanList=new ArrayList<>();
        claim= new ClaimVO();
        claims= new ArrayList<>();
        remitBeanList.add(remitBean);
        depositPostedAmt=new BigDecimal(-10);
        claimPostedAmt = new BigDecimal(-10);
        remitAmount=new BigDecimal(20);
        claims.add(claim);
    }
    private static void setFinalStatic(Field field, Object newValue) throws Exception{
        field.setAccessible(true);        
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }
    @Test
    public void testLucenePost_refund_success() throws SQLException{
        /* Set Data */
        remitBean.setRemitType("R");
        remitBean.setRemitAmt(remitAmount);
        remitBean.setDepositId(6866418);
        remitBean.setClaims(claims);
        depositPostedAmt=depositPostedAmt.add(new BigDecimal(20));
        claimPostedAmt=claimPostedAmt.add(new BigDecimal(10));
        claim.setClaimId(6866418);
        claim.setContractNum("100");
         Object[] depositParams = new Object[] { 6866418 };
         Object[] claimParams = new Object[] { 6866418,"100" };
        /* Record Invocations*/
        when(jdbcTemplate.queryForObject(eq(Constants.FETCH_DEPOSIT_POSTED_AMT), eq(BigDecimal.class), anyObject())).thenReturn(depositPostedAmt);
        when(jdbcTemplate.queryForObject(eq(Constants.FETCH_CLAIM_POSTED_AMOUNT), eq(BigDecimal.class), anyObject())).thenReturn(claimPostedAmt);
        doNothing().when(logger).error(anyString());
        /* Play the Service */
        service.lucenePost(remitBeanList);
        /* Verify Results */
        /* reset data to original value as in SetUp method*/
    }
Just for sake of completeness, here is my context class too,
为了完整起见,这里也是我的上下文类,
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.slf4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
@Configuration
public class TestConfig {
    @Mock JdbcTemplate jdbcTemplate;
    @Mock Logger logger;
    TestConfig(){
        MockitoAnnotations.initMocks(this); 
    }
    @Bean
    public RCMatchDaoImpl getRCMatchDaoImpl() {
        return new RCMatchDaoImpl();
    }
    @Bean
    public JdbcTemplate jdbcTemplate(){
        return jdbcTemplate;
    }
    @Bean
    public Logger logger(){
        return logger;
    }
}
采纳答案by Sabir Khan
I did use this (with Mockito 1.10.19):
我确实使用过这个(使用 Mockito 1.10.19):
when(jdbcTemplate.queryForObject(eq(Constants.FETCH_DEPOSIT_POSTED_AMT), eq(BigDecimal.class), anyVararg())).thenReturn(depositPostedAmt);
when(jdbcTemplate.queryForObject(eq(Constants.FETCH_CLAIM_POSTED_AMOUNT), eq(BigDecimal.class), anyVararg())).thenReturn(claimPostedAmt);
and that is working as expected. Output:
这按预期工作。输出:
10
0 
as expected.
正如预期的那样。
Some reading: http://site.mockito.org/mockito/docs/current/org/mockito/ArgumentMatchers.html#anyVararg()
一些阅读:http: //site.mockito.org/mockito/docs/current/org/mockito/ArgumentMatchers.html#anyVararg()
Code used:
使用的代码:
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = RCMatchDaoImplTest.TestConfig.class, loader = AnnotationConfigContextLoader.class)
public class RCMatchDaoImplTest {
    @Autowired
    private RCMatchDaoImpl service;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private Logger logger;
    private RemitBean remitBean;
    private List<RemitBean> remitBeanList;
    private BigDecimal depositPostedAmt, claimPostedAmt, remitAmount;
    private ClaimVO claim;
    private List<ClaimVO> claims;
    @Before
    public void setUp() throws NoSuchFieldException, SecurityException, Exception {
        /* Set dependencies*/
        service.setJdbcTemplate(jdbcTemplate);
        setFinalStatic(RCMatchDaoImpl.class.getDeclaredField("logger"), logger);
        remitBean = new RemitBean();
        remitBeanList = new ArrayList<>();
        claim = new ClaimVO();
        claims = new ArrayList<>();
        remitBeanList.add(remitBean);
        depositPostedAmt = new BigDecimal(-10);
        claimPostedAmt = new BigDecimal(-10);
        remitAmount = new BigDecimal(20);
        claims.add(claim);
    }
    private static void setFinalStatic(Field field, Object newValue) throws Exception {
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }
    @Test
    public void testLucenePost_refund_success() throws SQLException {
        /* Set Data */
        remitBean.setRemitType("R");
        remitBean.setRemitAmt(remitAmount);
        remitBean.setDepositId(6866418);
        remitBean.setClaims(claims);
        depositPostedAmt = depositPostedAmt.add(new BigDecimal(20));
        claimPostedAmt = claimPostedAmt.add(new BigDecimal(10));
        claim.setClaimId(6866418);
        claim.setContractNum("100");
        Object[] depositParams = new Object[]{6866418};
        Object[] claimParams = new Object[]{6866418, "100"};
        /* Record Invocations*/
        when(jdbcTemplate.queryForObject(eq(Constants.FETCH_DEPOSIT_POSTED_AMT), eq(BigDecimal.class), anyVararg())).thenReturn(depositPostedAmt);
        when(jdbcTemplate.queryForObject(eq(Constants.FETCH_CLAIM_POSTED_AMOUNT), eq(BigDecimal.class), anyVararg())).thenReturn(claimPostedAmt);
        doNothing().when(logger).error(anyString());
        /* Play the Service */
        service.lucenePost(remitBeanList);
        /* Verify Results */
        /* reset data to original value as in SetUp method*/
    }
    @Configuration
    public static class TestConfig {
        @Mock
        JdbcTemplate jdbcTemplate;
        @Mock
        Logger logger;
        TestConfig() {
            MockitoAnnotations.initMocks(this);
        }
        @Bean
        public RCMatchDaoImpl getRCMatchDaoImpl() {
            return new RCMatchDaoImpl();
        }
        @Bean
        public JdbcTemplate jdbcTemplate() {
            return jdbcTemplate;
        }
        @Bean
        public Logger logger() {
            return logger;
        }
    }
    public static class RCMatchDaoImpl {
        public static final Logger logger = LoggerFactory.getLogger(RCMatchDaoImpl.class);
        private JdbcTemplate jdbcTemplate;
        public void setJdbcTemplate(final JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
        public void lucenePost(final List<RemitBean> remitBeanList) {
            for (RemitBean remitBean : remitBeanList) {
                System.out.println(jdbcTemplate.queryForObject(Constants.FETCH_DEPOSIT_POSTED_AMT, BigDecimal.class, new Object[]{remitBean.getDepositId()}));
                for (ClaimVO claimVO : remitBean.getClaims()) {
                    System.out.println(jdbcTemplate.queryForObject(Constants.FETCH_CLAIM_POSTED_AMOUNT, BigDecimal.class, new Object[]{claimVO.getClaimId(), remitBean.getContractNum()}));
                }
            }
        }
    }
    public static class RemitBean {
        private String remitType;
        private BigDecimal remitAmt;
        private int depositId;
        private List<ClaimVO> claims;
        private Object contractNum;
        public void setRemitType(final String remitType) {
            this.remitType = remitType;
        }
        public void setRemitAmt(final BigDecimal remitAmt) {
            this.remitAmt = remitAmt;
        }
        public void setDepositId(final int depositId) {
            this.depositId = depositId;
        }
        public int getDepositId() {
            return depositId;
        }
        public void setClaims(final List<ClaimVO> claims) {
            this.claims = claims;
        }
        public List<ClaimVO> getClaims() {
            return claims;
        }
        public Object getContractNum() {
            return contractNum;
        }
    }
    public static class ClaimVO {
        private int claimId;
        private String contractNum;
        public void setClaimId(final int claimId) {
            this.claimId = claimId;
        }
        public int getClaimId() {
            return claimId;
        }
        public void setContractNum(final String contractNum) {
            this.contractNum = contractNum;
        }
    }
    static class Constants {
        public static final String FETCH_DEPOSIT_POSTED_AMT = "1";
        public static final String FETCH_CLAIM_POSTED_AMOUNT = "2";
    }
}

