mercredi 30 septembre 2015

JOOQ MockDataProvider - how to return different mocks depending on some conditions?

Recenty I was implementing unit test using JOOQ MockDataProvider. When I wanted to use my mock provider in DAO with many selects I had to use many if-else statements. According to: http://ift.tt/1O7oFNU , I just need to check if my SQL starts with some query. And my SQLs used in DAO could start with 3 different ways, so I used pretty complex if-else construct. Second thing - I wanted my MockDataProvider to return some mock result only when SQL is executed for the first time, and then to not return any results - in DAO iterated in loop 5 times, and each time my DAO should check something in database.I had no idea how to mock such behaviour, so I used simple counter - but it looks awful, and I want it to be implemented in a good way. Here is my code:

public class SomeProvider implements MockDataProvider {

private static final String STATEMENT_NOT_SUPPORTED_ = "Statement not supported: ";
private static final String SELECT_META = "select \"myschema\".\"meta\".";
private static final String SELECT_CLIENT = "select \"myschema\".\"client\".";
private static final String SELECT_KEY = "select \"myschema\".\"key\".";
private static final String TEST_SECRET_KEY = "some key";
private static final String KEY = "40sld";
private static final String DROP = "DROP";
private static final String SOME_URL = "something";
private static final String MONKEY = "monkey";
private static final int FIRST_ITERARION_COUNTER_VALUE = 0;
private final Long keyId;
int counter = 0;

public SomeProvider(Long keyId) {
    this.keyId = keyId;
}

@Override
public MockResult[] execute(MockExecuteContext ctx) throws SQLException {

    DSLContext create = DSL.using(SQLDialect.POSTGRES);
    MockResult[] mock = new MockResult[3];
    String sql = ctx.sql();
    if (sql.toUpperCase().startsWith(DROP)) {
        throw new SQLException(STATEMENT_NOT_SUPPORTED_ + sql);
    } else if (sql.startsWith(SELECT_CLIENT)) {

        Result<ClientRecord> result = create.newResult(CLIENT);
        result.add(create.newRecord(CLIENT));
        result.get(0).setValue(CLIENT.ID, 1L);
        result.get(0).setValue(CLIENT.SECRET_KEY, TEST_SECRET_KEY);
        mock[0] = new MockResult(1, result);

    } else if (sql.startsWith(SELECT_META)) {

        Result<MetaRecord> metaResult = create.newResult(META);
        metaResult.add(create.newRecord(META));
        metaResult.get(0).setValue(META.ID, 1L);

        metaResult.get(0).setValue(META.URL, SOME_URL);
        metaResult.get(0).setValue(META.KEY, KEY);
        metaResult.get(0).setValue(META.OPTION, keyId);
        mock[0] = new MockResult(1, metaResult);

    } else if (sql.startsWith(SELECT_KEY)) {

        Result<KeyRecord> keyResult = create.newResult(KEY);
        if (counter == FIRST_ITERARION_COUNTER_VALUE) {
            // first SELECT returns monkey, rest will return no results
            keyResult.add(create.newRecord(KEY));
            keyResult.get(0).setValue(KEY.ID, 1L);
            keyResult.get(0).setValue(KEY.VALUE, MONKEY);
            mock[0] = new MockResult(1, keyResult);
        } else {
            mock[0] = new MockResult(0, keyResult);
        }
        counter++;
    }

    return mock;
}

}

It works but looks bad. To sum up my question is: How to return (using one provider) different results depending on the query and the number of query execution. Maybe this class is only for simple DSLContext mocking, not to mock whole DAO which uses many queries many times using one DSLContext.

Aucun commentaire:

Enregistrer un commentaire