Mocking an empty result set

1,443 views
Skip to first unread message

Deven Phillips

unread,
Jun 24, 2014, 9:24:58 AM6/24/14
to jooq...@googlegroups.com
I would like to know if someone could explain what I am doing wrong here...

I have created an implementation of MockDataProvider which always returns an empty result set:

private class EmptyResultsDataProvider implements MockDataProvider {
@Override
public MockResult[] execute(MockExecuteContext ctx) throws SQLException {
MockResult[] mock = new MockResult[1];
mock[0] = new MockResult(0, null);
return mock;
}
}

But, when I try to run a query using that MockDataProvider, I get a NullPointerException instead of a null result from fetchOne()???

I have another MockDataProvider that actually returns data for that same query, and it runs fine.

Any thoughts or suggestions?

Thanks in advance!!

Deven

Deven Phillips

unread,
Jun 24, 2014, 9:31:44 AM6/24/14
to jooq...@googlegroups.com
OK, back to answer my own question!!!

The problem was that I needed to create the empty Result object with no members:

private class EmptyResultsDataProvider implements MockDataProvider {
@Override
public MockResult[] execute(MockExecuteContext ctx) throws SQLException {
MockResult[] mock = new MockResult[1];
Result<Record4<String>> result = create.newResult(...);
mock[0] = new MockResult(0, result);
return mock;

Lukas Eder

unread,
Jun 24, 2014, 11:13:57 AM6/24/14
to jooq...@googlegroups.com
Hi,

Yes, if you provide "null" to the MockResult, you will get a somewhat invalid result with no columns from your statement.

Do you think there is room for improvement in that area?

Cheers,
Lukas


--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Deven Phillips

unread,
Jun 24, 2014, 12:14:19 PM6/24/14
to jooq...@googlegroups.com
Lukas,

    There's definitely room for improving the documentation around the MockDataProvider... There are MANY cases where I would like to use the bind values to help determine the result sets and that is not documented anywhere other than playing with the API. I will try to write up some concise docs on using the bind values as well as the query matching to be added. Other than that, I imagine it would be ideal to just somehow pass an identifier somehow so that you can explicitly choose a mock result for each query... I'm not sure what that would look like or how it could be implemented; but I will think on it..

Cheers,

Deven

Deven Phillips

unread,
Jun 24, 2014, 12:41:06 PM6/24/14
to jooq...@googlegroups.com
Heh! I just had a brainstorm!!

Instead of using a complicated tree of if/then/else if/else statements to determine which Mock data to return, could we allow developers to use a selector? For example, if your MockDataProvider exposed a method like:

public void setSelector(int value);

And before running your test code, you would call:

mockDataProvider.setSelector(0);

And in the MockDataProvider, we could just use the value of that selector to determine which resultset to provide?

That would certainly make the code more readable! Instead of complicated boolean tests on strings and bind values, we could set up descriptive constants for the various selectors like:

private static final int RETURN_USER_LIST_CASE1 = 0;
private static final int RETURN_USER_LIST_CASE2 = 1;
private static final int RETURN_GROUP_CASE1 = 2;
private static final int RETURN_GROUP_CASE2 = 3;
private static final int RETURN_GROUP_CASE3 = 4;

Thoughts?

Deven

Deven Phillips

unread,
Jun 24, 2014, 12:46:05 PM6/24/14
to jooq...@googlegroups.com
Oh, and this has the added benefit of not breaking backward compatibility. People who are already using the existing method need not change their code, but any new code could take advantage of the selector capability...

Deven

Deven Phillips

unread,
Jun 24, 2014, 12:57:01 PM6/24/14
to jooq...@googlegroups.com
I just tried to implement this and apparently the API does a copy of the MockDataProvider instance somewhere because the instance that I am running setSelector() on is not the same instance as that used to provide the mock results.... :(

Bummer...

Deven

Deven Phillips

unread,
Jun 24, 2014, 1:26:47 PM6/24/14
to jooq...@googlegroups.com
Alright, I have a plan and will get back with a pull request shortly...

Deven

Deven Phillips

unread,
Jun 24, 2014, 2:00:26 PM6/24/14
to jooq...@googlegroups.com
OK, pull request created.


I hope that this will be useful to lots of people, because I KNOW it would make my life lots easier!

Deven
Message has been deleted

Deven Phillips

unread,
Jun 24, 2014, 9:22:04 PM6/24/14
to jooq...@googlegroups.com
Pull request cancelled and recreated after implementing unit tests and more debugging.


Also, looks like the TravisCI builds are all passing and so it appears there will be no regressions by incorporating these changes...

Woot!

Deven

Lukas Eder

unread,
Jun 25, 2014, 4:22:07 AM6/25/14
to jooq...@googlegroups.com
Hi Deven,

I see you've been busy :) I'm trying to respond to all your mails in one.

    There's definitely room for improving the documentation around the MockDataProvider... There are MANY cases where I would like to use the bind values to help determine the result sets and that is not documented anywhere other than playing with the API. I will try to write up some concise docs on using the bind values as well as the query matching to be added. Other than that, I imagine it would be ideal to just somehow pass an identifier somehow so that you can explicitly choose a mock result for each query... I'm not sure what that would look like or how it could be implemented; but I will think on it..

Yes, that's true. The MockDataProvider has been introduced as an experimental API at first with little documentation. It looks like the general direction is fine, but we haven't been working on it much any more.

I'm curious about your bind variable use-case. Could you elaborate a bit more, perhaps?

2014-06-25 3:22 GMT+02:00 Deven Phillips <deven.p...@gmail.com>:
Pull request cancelled and recreated after implementing unit tests and more debugging.


I'll review that as soon as possible.

Also, looks like the TravisCI builds are all passing and so it appears there will be no regressions by incorporating these changes...

Woot!

Congrats ;-)

Deven Phillips

unread,
Jun 25, 2014, 6:39:25 AM6/25/14
to jooq...@googlegroups.com
Let me elaborate on what I am trying to accomplish with the MockDataProviders... Right now, the documentation explains that to retrieve different result sets, you should implement logic which looks at the generated SQL strings in order to choose which data to return. But, in my use case, I might want to return several different result sets for the exact same query so that I can test different branches of my DAOs, mappings, ReST responses, etc... This means that in the current API, I have to look at the bind variables in order to get different resultsets or I would have to create multiple implementations of MockDataProvider and MockConnection to cover my different branch requirements. Instead, it would be much cleaner to have the ability to just tell the MockConnection/MockDataProvider which resultset I want by having a "selector" which could then be used instead of writing if/then/else conditionals around the SQL string and bind variable values. I think that the unit tests I submitted with the pull request demonstrate the use case rather well..

Thanks,

Deven

Lukas Eder

unread,
Jun 25, 2014, 7:22:05 AM6/25/14
to jooq...@googlegroups.com
Hi Deven,

I understand your use-case, now, but I strongly object putting something so test-implementation-specific into the library. Nothing keeps you from implementing whatever logic you need in your own MockDataProvider implementation:

class MyLocalProvider implements MockDataProvider {
    int selector;

    @Override
    public MockResult[] execute(MockExecuteContext c) throws SQLException {
        DSLContext ctx = DSL.using(SQLDialect.POSTGRES);
        Field<Object> field = DSL.field("one");

        Result<Record1<Object>> result = ctx.newResult(field);
        result.add(ctx.newRecord(field));

        if (selector == 0) {
            result.get(0).setValue(field, 1);
            return new MockResult[] { new MockResult(1, result) };
        }
        else {
            // Sneaky bug emulation
            result.get(0).setValue(field, 2);
            return new MockResult[] { new MockResult(0, result) };
        }
    }
}

MyLocalProvider p = new MyLocalProvider();

// Note: INSERT .. RETURNING is hard to mock for all dialects...
DSLContext ctx = DSL.using(new MockConnection(p), SQLDialect.POSTGRES);

p.selector = 0;
System.out.println(ctx.selectOne().fetch());

p.selector = 1;
System.out.println(ctx.selectOne().fetch());

The above prints on the console:

+----+
| one|
+----+
|   1|
+----+

+----+
| one|
+----+
|   2|
+----+

So, why change the library for this feature?

--

Lukas Eder

unread,
Jun 25, 2014, 7:26:48 AM6/25/14
to jooq...@googlegroups.com
Disregard that comment, which I copy-pasted from another test case:

// Note: INSERT .. RETURNING is hard to mock for all dialects...

Deven Phillips

unread,
Jun 25, 2014, 4:51:31 PM6/25/14
to jooq...@googlegroups.com
OK, finally found some time this afternoon to do some testing. I created a simple test project where I was JUST writing tests and you are correct that it works as you said... The problem, in the end, was that when I passed the DSLContext into my DAO. By assigning the passed DSLContext instance to the DAO's private instance I was actually creating a closure where the selector value would not change. So, I changed my test to create a new instance of the DAO after each selector value change and it works perfectly!!

AWESOME! That seriously simplifies my workflow for testing. I greatly appreciate the feedback!

Deven  

Lukas Eder

unread,
Jun 25, 2014, 5:03:44 PM6/25/14
to jooq...@googlegroups.com
Great! Well, it simplified my maintenance, too :-)

Cheers
Lukas

rui...@money-design.com

unread,
Dec 12, 2016, 3:55:50 AM12/12/16
to jOOQ User Group

Hi Deven,

I have the same problem wit you. I try to build test cases for the service which get user by userId, while I could not write a good test case of the scenario which userId is not in the db. Still have no idea after read the following discussion. But, I believe what I want to do it's just like your question here. Could you share your ideas?

Thank you  very much!
Gao Rui
Reply all
Reply to author
Forward
0 new messages