Junit Как смоделировать namedParameterJdbcTemplate.query ("", параметры, (ResultSet rs)) - PullRequest
2 голосов
/ 30 апреля 2020

Я пишу контрольные примеры для классов репозитория, где я не могу охватить некоторые строки в классах репозитория. Мне нужно достичь 85% покрытия кода и его обязательна в моем случае. Пожалуйста, предложите мне что-нибудь

Мой фактический метод

public Map<String, String> getProductFamily(List<String> itmNms) {

        Map<String, String> productFamilyMap=new HashMap<String, String>();
        try {
        NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
        String sql = "some query";
        MapSqlParameterSource namedParameters = new MapSqlParameterSource();
        namedParameters.addValue("itmNms", itmNms);
        productFamilyMap = namedParameterJdbcTemplate.query(sql, namedParameters, (ResultSet rs) -> {
            Map<String, String> productFamily = new HashMap<>();
            while (rs.next()) {
                productFamily.put(rs.getString("ITEMNAME"), rs.getString("PRODUCTFAMILY"));
            }
            return productFamily;
        });
        }catch (Exception e) {
            LOGGER.error("Exception in OracleRespository.getProductFamily : {}", e);
        }
        return productFamilyMap;
    }

Контрольный пример для вышеприведенный метод

@Test
    public void getProductFamily() {

    List<String> itmNms = new ArrayList<String>();
    itmNms.add("A-SPK-NAMED-USER");
    oracleRepo.getProductFamily(itmNms);
    Map<String, String> mp = new HashMap<String, String>();
    Assert.assertNull(mp);

}

Записав вышеприведенные тестовые примеры, я могу охватить покрытие кода до строки № 6, а за строки, которую я не могу охватить, из-за следующих утверждений

productFamilyMap = namedParameterJdbcTemplate.query(sql, namedParameters, (ResultSet rs) ->{}

Может ли кто-нибудь предложить, как я могу достичь покрытия кода для вышеуказанного метода как 100%.

1 Ответ

1 голос
/ 03 мая 2020

В таких случаях вам нужно «вручную вызвать» код в лямбде. Это может быть выполнено с Mockito.doAnswer(...) функциональностью Mockito framework. Пример (подходит для Mockito 2 +):

Mockito.doAnswer(invocationOnMock -> {

    ResultSet resultSet = Mockito.mock(ResultSet.class);
    Mockito.when(resultSet.next()).thenReturn(true).thenReturn(false);
    Mockito.when(resultSet.getString("ITEMNAME")).thenReturn(...);
    Mockito.when(resultSet.getString("PRODUCTFAMILY")).thenReturn(...);

    ResultSetExtractor<Map<String, String>> resultSetExtractor = 
        invocationOnMock.getArgument(2);
    return resultSetExtractor.extractData(resultSet);

}).when(namedParameterJdbcTemplate).query(
    Mockito.anyString(), 
    Mockito.any(MapSqlParameterSource.class), 
    Mockito.any(ResultSetExtractor.class)
);

Затем вы можете проверить productFamilyMap для заполненной пары ключ-значение.

Если у вас все еще есть проблемы с этим, вы могу поделиться своим кодом (например, через Github), и я постараюсь помочь вам с этим.

РЕДАКТИРОВАТЬ: Изначально я не заметил, что NamedParameterJdbcTemplate создается вручную с new, и издеваться над ним довольно сложно. В этом случае лучше немного реорганизовать свой производственный код - вы можете создать объект NamedParameterJdbcTemplate как bean-компонент (как вы, вероятно, сделали с raw JdbcTemplate), а затем внедрить его в свой класс (и из c удалить строку где вы создаете это с new). Тогда вещи становятся тривиальными.

@Component
public class OracleRepository {

    private static final Logger LOGGER = LoggerFactory.getLogger(OracleRepository.class);

    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate; //created as bean in configuration class

    public Map<String, String> getProductFamily(List<String> itmNms) {

        Map<String, String> productFamilyMap=new HashMap<String, String>();
        try {
            String sql = "some query";
            MapSqlParameterSource namedParameters = new MapSqlParameterSource();
            namedParameters.addValue("itmNms", itmNms);
            productFamilyMap = namedParameterJdbcTemplate.query(sql, namedParameters, (ResultSet rs) -> {
                Map<String, String> productFamily = new HashMap<>();
                while (rs.next()) {
                    productFamily.put(rs.getString("ITEMNAME"), rs.getString("PRODUCTFAMILY"));
                }
                return productFamily;
            });
        }catch (Exception e) {
            LOGGER.error("Exception in OracleRespository.getProductFamily : {}", e);
        }
        return productFamilyMap;
    }
}

Тестовый класс остается неизменным:

@RunWith(MockitoJUnitRunner.class)
public class OracleRepositoryTest {

    @InjectMocks
    private OracleRepository oracleRepo;

    @Mock
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    @Test
    public void getProductFamily() {
        List<String> itmNms = new ArrayList<>();
        itmNms.add("A-SPK-NAMED-USER");

        Mockito.doAnswer(invocationOnMock ->{
            ResultSet resultSet = Mockito.mock(ResultSet.class);
            Mockito.when(resultSet.next()).thenReturn(true).thenReturn(false);
            Mockito.when(resultSet.getString("ITEMNAME")).thenReturn("A-SPK-NAMED-USER");
            Mockito.when(resultSet.getString("PRODUCTFAMILY")).thenReturn("SPKCLD");

            ResultSetExtractor<Map<String, String>> resultSetExtractor =
                    invocationOnMock.getArgument(2);
            return resultSetExtractor.extractData(resultSet);

        }).when(namedParameterJdbcTemplate).query(
                Mockito.anyString(),
                Mockito.any(MapSqlParameterSource.class),
                Mockito.any(ResultSetExtractor.class)
        );

        Map<String, String> productFamilyMap = oracleRepo.getProductFamily(itmNms);

        Assert.assertEquals("SPKCLD", productFamilyMap.get("A-SPK-NAMED-USER"));
    }
}
...