How to simulate a DB for testing (Java)?

后端 未结 14 1399
走了就别回头了
走了就别回头了 2020-11-30 19:15

I\'m programming in Java and my applications are making a lot of use of DB. Hence, it is important for me to be able to test my DB usage easily.
What DB tests are all ab

14条回答
  •  旧巷少年郎
    2020-11-30 19:40

    jOOQ is a tool that apart from offering SQL abstraction also has small tools built in such as an SPI that allows for mocking the entirety of JDBC. This can work in two ways as documented in this blog post:

    By implementing the MockDataProvider SPI:

    // context contains the SQL string and bind variables, etc.
    MockDataProvider provider = context -> {
    
        // This defines the update counts, result sets, etc.
        // depending on the context above.
        return new MockResult[] { ... }
    };
    

    In the above implementation, you can programmatically intercept every SQL statement and return a result for it, even dynamically by "parsing" the SQL string to extract some predicates / table information, etc.

    By using the simpler (but less powerful) MockFileDatabase

    ... which has a format like the following (a set of statement / result pairs):

    select first_name, last_name from actor;
    > first_name last_name
    > ---------- ---------
    > GINA       DEGENERES
    > WALTER     TORN     
    > MARY       KEITEL   
    @ rows: 3
    

    The above file can then be read and consumed as follows:

    import static java.lang.System.out;
    import java.sql.*;
    import org.jooq.tools.jdbc.*;
    
    public class Mocking {
        public static void main(String[] args) throws Exception {
            MockDataProvider db = new MockFileDatabase(
                Mocking.class.getResourceAsStream("/mocking.txt");
    
            try (Connection c = new MockConnection(db));
                Statement s = c.createStatement()) {
    
                out.println("Actors:");
                out.println("-------");
                try (ResultSet rs = s.executeQuery(
                    "select first_name, last_name from actor")) {
                    while (rs.next())
                        out.println(rs.getString(1) 
                            + " " + rs.getString(2));
                }
            }
        }
    }
    

    Notice how we're using the JDBC API directly, without actually connecting to any database.

    Do note, I work for the vendor of jOOQ so this answer is biased.

    Beware, at some point, you're implementing an entire database

    The above works for simple cases. But beware that, eventually, you will be implementing an entire database. You want:

    1. Verify SQL syntax.

    OK, by mocking the database as shown above, you can "verify" syntax, because each syntax that you haven't foreseen in the exact version as listed above will be rejected by any such mocking approach.

    You could implement a parser that parses SQL (or, again, use jOOQ's), and then transform the SQL statement into something you can more easily recognise and produce a result for. But ultimately, this just means implementing an entire database.

    1. More importantly, check that the data is selected/updated/inserted correctly, according to a given situation.

    This makes things even harder. If you run an insert and then update, the result is obviously different from update first, then insert, as the update may or may not affect the inserted row.

    How do you make sure this happens when "mocking" a database? You need a state machine that remembers the state of each "mocked" table. In other words, you'll implement a database.

    Mocking will only take you this far

    As piotrek mentioned, too, mocking will only take you this far. It is useful in simple cases when you need to intercept only a few very well known queries. It is impossible, if you want to mock the database for an entire system. In that case, use an actual database, ideally the same product that you're using in production.

提交回复
热议问题