1

I'm creating new unit tests for an application and I'm stuck because the KeyHolder is not returning a valid object.

For context, here are my classes:

ScriptDao class:

@Repository
public class ScriptDao extends DefaultDao {

    private static final Logger LOG = LoggerFactory.getLogger(ScriptDao.class);

    public Long save(ScriptModel script) {
        LOG.debug("saving script {}", script);

        String sql = "INSERT INTO " + DBTable.SCRIPT + " (script_type_id, hash, content) " +
                "VALUES(?, ?, ?)";

        List<Object> queryParams = new LinkedList<>();
        queryParams.add(script.getScriptType());
        queryParams.add(script.getHash());
        queryParams.add(script.getContent());

        KeyHolder keyHolder = save(sql, queryParams);

        return keyHolder.getKey() != null ? keyHolder.getKey().longValue() : null;
    }
}

DefaultDao class:

@Repository
public class DefaultDao {

    @Autowired
    protected ObjectMapper jacksonObjectMapper;

    @Autowired
    protected JdbcTemplate jdbcTemplate;

    public KeyHolder save(String sql, List queryParams) {
        Object[] parameters = queryParams.toArray();
        printSQL(sql);
        printParams(queryParams);
        KeyHolder keyHolder = new GeneratedKeyHolder();
        int rowAffected = jdbcTemplate.update(getPreparedStatementCreator(sql, parameters), keyHolder);
        getLogger().debug("operation successfully completed on {} rows", rowAffected);
        return keyHolder;
    }
}

Test case:

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class ScriptDaoTest {

    @InjectMocks
    private ScriptDao scriptDao;

    @Mock
    private JdbcTemplate jdbcTemplate;

    @Mock
    private SqlRowSet sqlRowSet;

    @Mock
    private DefaultDao defaultDao;

    @Test
    void testSaveMethod() {
        ScriptModel script = new ScriptModel();
        script.setScriptType(1);
        script.setHash("hash123");
        script.setContent("content");

        Map<String, Object> keyMap = new HashMap<String, Object>();
        keyMap.put("", 1L);

        KeyHolder keyHolder = new GeneratedKeyHolder();
        List<Map<String, Object>> generatedKeys = keyHolder.getKeyList();
        generatedKeys.clear();
        generatedKeys.add(keyMap);

        when(defaultDao.save(anyString(), anyList())).thenReturn(keyHolder);

        Long result = scriptDao.save(script);

        assertEquals(1L, result);
    }
}

When I run the unit test it does fail in the assertEquals with the following message:

org.opentest4j.AssertionFailedError: 
Expected :1
Actual   :null
<Click to see difference>


    at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
    at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
    at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
    at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
    at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
    at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:639)
    at com.xxxxxxx.daos.ScriptDaoTest.testSaveMethod(ScriptDaoTest.java:62)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at java.util.ArrayList.forEach(ArrayList.java:1259)


Process finished with exit code -1

I've added some log messages in the test case and I can see the keyHolder has the correct value, but it seems like the defaultDao.save() is not using the keyHolder defined in the unit test.

I expected that my assertEquals will be true as the KeyHolder in the unit test was hardcoded to be 1.

1
  • 3
    The ScriptDao does not habe field of type DefaultDao, thus creating a mock of type DefaultDao and defining mock behaviour on it has no effect. What you are looking for is most probably a stub or spy, so you can partially mock ScriptDao while not mocking other methods.
    – Turing85
    Commented Jul 1 at 15:44

1 Answer 1

0

Thanks @Turing85, after your comment I've changed the unit test the following and now it does work!

@Test
void testSaveMethod() {
    ScriptModel script = new ScriptModel();
    script.setScriptType(1);
    script.setHash("hash123");
    script.setContent("content");

    doAnswer(invocation -> {
        KeyHolder keyHolder = invocation.getArgument(1);
        Map<String, Object> keyMap = new HashMap<String, Object>();
        keyMap.put("", 1L);
        List<Map<String, Object>> generatedKeys = keyHolder.getKeyList();
        generatedKeys.clear();
        generatedKeys.add(keyMap);
        return 1;
    }).when(jdbcTemplate).update(any(), any(KeyHolder.class));

    Long result = scriptDao.save(script);

    assertEquals(1L, result);
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.