Over a million developers have joined DZone.

Stubbing Key-Value Stores

DZone's Guide to

Stubbing Key-Value Stores

Everyone who works on a database project faces the dilemma how to test database-dependent code. Stubbing is a good option to keep in your testing toolbox.

· Database Zone ·
Free Resource

MariaDB TX, proven in production and driven by the community, is a complete database solution for any and every enterprise — a modern database for modern applications.

Every project that has a database has a dilemma when it comes to how to test database-dependent code. There are several options (not mutually exclusive):

  • Use mocks. Only use unit tests and mock the data-access layer, assuming the DAO-to-database communication works.
  • Use an embedded database that each test starts and shuts down. This can also be viewed as unit testing.
  • Use a real database deployed somewhere (either locally or on a test environment). The hard part is making sure it's always in a clean state.
  • Use end-to-end/functional tests/BDD/UI tests after deploying the application on a test server (which has a proper database).

None of the above is without problems. Unit tests with mocked DAOs can't really test more complex interactions that rely on a database state. Embedded databases are not always available (for example, if you are using a non-relational database or if you rely on RDBMS-specific functionality, HSQLDB won't do), or they can be slow to start. This means your tests may take too long in supporting. A real database installation complicates setup, and keeping it clean is not always easy. The coverage of end-to-end tests can't be easily measured and they don't necessarily cover all the edge cases, as they are harder to maintain than unit and integration tests.

I've recently tried a strange approach that is working pretty well so far: stubbing the database. It is applicable more to key-value stores and less to relational databases.

In my case, even though there is embedded Cassandra, it was slow to start, wasn't easy to set up, and had subtle issues. That's why I replaced the whole thing with an in-memory ConcurrentHashMap.

Since I'm using spring-data-cassandra, I just extended the CassandraTemplate class, implemented all the methods in the new StubCassandraTemplate, and used it instead of the regular one in the test Spring context. The stub can support all the key-value operations pretty easily and you can have a bit more complicated integration tests (it's not a good idea to have very complicated tests, of course, but unit tests can either be too simple or too reliant on a lot of mocks). Here's an excerpt from the code:

public class StubCassandraTemplate extends CassandraTemplate {

    private Map<Class<?>, Map<Object, Object>> data = new ConcurrentHashMap<>();

    public void afterPropertiesSet() {
        // no validation

    public <T> T insert(T entity) {
        List<Field> pk = FieldUtils.getFieldsListWithAnnotation(entity.getClass(), PrimaryKey.class);
        try {
            return (T) data.get(entity.getClass()).put(pk.get(0).get(entity), entity);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException(e);

    private <T> void initializeClass(Class<?> clazz) {
        if (data.get(clazz) == null) {
            data.put(clazz, new ConcurrentHashMap<>());

Cassandra supports some advanced features like CQL (query language), which isn't as easy to stub as key-value operations like GET and PUT, but in fact, it is not that hard — especially if you don't rely on complicated WHERE clauses (and this is a bad practice in Cassandra, anyway), it's easy to parse the query with regex and find the appropriate entries in the ConcurrentHashMap.

Key-value stores are a good candidate for this approach, as their main advantage — being easy to scale horizontally — is not needed in an integration test scenario. You simply need to verify that your code correctly handles interactions with the database in terms of what it puts there and what it gets back. The exact implementation of that interaction, whether it's in-memory or using a binary protocol, may be viewed as out-of-scope.

Note that these tests do not guarantee that the application will work with a real database. They only guarantee that it will behave properly if the database behaves the same way as an in-memory key-value data structure, which is normally the assumption, but isn't always true — for example, the database can impose additional constraints that your stub implementation doesn't have. Cassandra, for example, doesn't allow WHERE queries for non-indexed columns. If you don't take that into account, obviously, your test will pass, but your application will break.

That's why you'd still need end-to-end tests and possibly some real integration tests, but you can cover most of the code with a simple in-memory stub and only do some "sanity" full integration tests.

This doesn't mean you should always stub your database, but it's a good option in your testing toolbox to consider.

MariaDB AX is an open source database for modern analytics: distributed, columnar and easy to use.

database ,key-value stores ,tutorial ,cassandra ,software testing ,stub

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}