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.
ScriptDao
does not habe field of typeDefaultDao
, thus creating a mock of typeDefaultDao
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 mockScriptDao
while not mocking other methods.