Java 使用发出DB调用来存根/模拟方法时出现问题

Java 使用发出DB调用来存根/模拟方法时出现问题,java,unit-testing,mocking,mockito,Java,Unit Testing,Mocking,Mockito,我对使用MockitoJUnitRunner模拟JDBC调用有意见。 莫名其妙的是,Mockito并没有模拟实际的调用,即使我在测试类中有下面的子行 when(readOnlyJdbcTemplate.query(anyString(), any(Object[].class), any(int[].class), any(FeatureCollectionResponseExtractor.class))).thenReturn(actual); @RunWith(MockitoJUnitR

我对使用MockitoJUnitRunner模拟JDBC调用有意见。 莫名其妙的是,Mockito并没有模拟实际的调用,即使我在测试类中有下面的子行

when(readOnlyJdbcTemplate.query(anyString(), any(Object[].class), any(int[].class), any(FeatureCollectionResponseExtractor.class))).thenReturn(actual);
@RunWith(MockitoJUnitRunner.class)
public class FeatureLibraryDaoImplTest {

    @InjectMocks
    private FeatureLibraryDaoImpl dao;

    @Mock
    private JdbcTemplate readOnlyJdbcTemplate;

    private List<String> features = Arrays.asList("excl_clsd_ind_only", "excl_chrgoff_ind_only", "excl_dsput_ind_only");

    @Test
    public void getFeaturesDataWhenSuccess() {
        //given
        FeatureRequest request = getFeatureRequest();
        FeatureCollectionDTO actual = new FeatureCollectionDTO(features);

        when(readOnlyJdbcTemplate.query(anyString(), any(Object[].class), any(int[].class), any(FeatureCollectionResponseExtractor.class))).thenReturn(actual);

        //when
        FeatureCollectionDTO dto = dao.getFeaturesData(request);

        //then
        assertThat(dto, notNullValue());
    }
}
非常相似的模拟在另一个类中用于非常相似类型的方法。它们之间唯一的区别是我的另一个类有3个参数,而不是4个参数。下面是实际为不同类成功模拟的代码

when(readOnlyJdbcTemplate.query(anyString(), any(Object[].class), any(FeaturesResultExtractor.class))).thenReturn(actual);
下面是我的实际代码

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.inject.Inject;
import javax.inject.Named;
import java.net.HttpURLConnection;
import java.sql.Types;

import static com.accounts.features.utils.Constants.INTERNAL_SERVER_ERROR;

@Profile
@Log
@Named("featureLibraryDao")
public class FeatureLibraryDaoImpl implements FeatureLibraryDao {

    private static final Logger LOGGER = LogManager.getLogger(FeatureLibraryDaoImpl.class);

    @Value("${feature.library.function.sql.query}")
    private String sqlSelectQuery;

    @Inject
    @Named("readOnlyJdbcTemplate")
    private JdbcTemplate readOnlyJdbcTemplate;

    @Override
    public FeatureCollectionDTO getFeaturesData(FeatureRequest request) {
        try {
            int[] argTypes = new int[] { Types.BIGINT, Types.VARCHAR, Types.SMALLINT};
            return readOnlyJdbcTemplate.query(sqlSelectQuery, new Object[] {
                        Long.parseLong(request.getAccountId()), request.getRequestedFeatures(), request.getApplicationSuffix()
                    }, argTypes,
                    new FeatureCollectionResponseExtractor(request));
        } catch (CustomException cbe) {
            throw cbe;
        } catch (Exception ex) {
            LOGGER.error("getFeaturesData method failed with error message:{}", ex.getMessage(), ex);

            CustomErrorCode error = new CustomErrorCode(INTERNAL_SERVER_ERROR);
            error.setDeveloperText(ex.getMessage());
            throw new CustomSystemException(error, HttpURLConnection.HTTP_INTERNAL_ERROR);
        }
    }

}
下面是我的测试课

when(readOnlyJdbcTemplate.query(anyString(), any(Object[].class), any(int[].class), any(FeatureCollectionResponseExtractor.class))).thenReturn(actual);
@RunWith(MockitoJUnitRunner.class)
public class FeatureLibraryDaoImplTest {

    @InjectMocks
    private FeatureLibraryDaoImpl dao;

    @Mock
    private JdbcTemplate readOnlyJdbcTemplate;

    private List<String> features = Arrays.asList("excl_clsd_ind_only", "excl_chrgoff_ind_only", "excl_dsput_ind_only");

    @Test
    public void getFeaturesDataWhenSuccess() {
        //given
        FeatureRequest request = getFeatureRequest();
        FeatureCollectionDTO actual = new FeatureCollectionDTO(features);

        when(readOnlyJdbcTemplate.query(anyString(), any(Object[].class), any(int[].class), any(FeatureCollectionResponseExtractor.class))).thenReturn(actual);

        //when
        FeatureCollectionDTO dto = dao.getFeaturesData(request);

        //then
        assertThat(dto, notNullValue());
    }
}
@RunWith(MockitoJUnitRunner.class)
公共类功能库DAOMPLETEST{
@注射模拟
私人特色图书馆;
@嘲弄
私有JdbcTemplate只读JdbcTemplate;
private List features=Arrays.asList(“仅限excl_clsd_indu”、“仅限excl_chrgoff_indu”、“仅限excl_dsput_indu”);
@试验
public void getFeaturesDataWhenSuccess(){
//给定
FeatureRequest=getFeatureRequest();
FeatureCollectionDTO实际=新FeatureCollectionDTO(特征);
当(只读jdbctemplate.query(anyString()、any(Object[].class)、any(int[].class)、any(FeatureCollectionResponseExtractor.class))。然后返回(实际);
//什么时候
FeatureCollectionDTO dto=dao.getFeaturesData(请求);
//然后
断言(dto,notNullValue());
}
}

关于这里的问题有什么建议吗?
any(int[].class)
是否有任何问题?

我确实看到您在测试用例期间没有传递sql查询
sqlSelectQuery
值,但在mock期间指定了
anyString()
,因此它必须是某个值,但不能为null。由于您使用的是
spring
project,因此可以使用
ReflectionTestUtils
设置对象的字段值

@Before
public void setUp() {
    ReflectionTestUtils.setField(dao, "sqlSelectQuery", "query");

}

嘿,伙计们,谢谢你们的建议。所以我发现测试代码非常好。一些
@Value
标记没有将实际值注入主代码文件中的
sqlSelectQuery
@Value(“${feature.library.function.sql.query}”)私有字符串sqlSelectQuery

我将代码改为
私有字符串sqlSelectQuery=“${feature.library.function.sql.query}”
,所有测试用例都通过了


不知何故,
sqlSelectQuery
没有得到值,因此Mockito没有模拟实际的方法调用。我还在回顾为什么
@value
不能正常工作

它是否返回
null
或任何错误消息?是的,它返回null您是否尝试了
any()
以检查参数的类型是否都正确?还要检查在mock
new org.mockito.internal.util.MockUtil().getMockHandler(readOnlyJdbcTemplate.getInvocationContainer().getInvocations()
@Deadpool上注册的调用如果没有注入mock,那么OP应该得到一个NPE吗?我想我发现了这个问题,请尝试用
isNull()
代替
anyString()
第一个参数@user3452558原因是
mockito
@值
注释无关。因此它被忽略了。您可能需要在此上下文中使用一些可以解析的内容,或者按照
Deadpool
的建议,您需要手动设置一个值。谢谢Deadpool。。!!