【问题标题】:JUnit testing SQL queriesJUnit 测试 SQL 查询
【发布时间】:2017-09-30 12:52:29
【问题描述】:

我正在做一个项目,我们需要创建一些测试用例。我有一个 SQL 数据库,并通过如下查询解析数据:

public Contractor create(String name, String address, String email, String phone, String city, int cvr) throws SQLException{
    Contractor contractor = new Contractor(name, address, email, phone, city, cvr);
    String sql = String.format("INSERT INTO person (name, address, email, phone, city, category) VALUES ('%s', '%s', '%s', '%s', '%s', 2)", name, address, email, phone, city);
    try{
        Connection conn = DBConnection.getInstance().getDBcon();
        conn.createStatement().executeUpdate(sql);

        String sql2 = "SELECT TOP 1 id FROM Person ORDER BY id DESC";
        ResultSet rs = conn.createStatement().executeQuery(sql2);

        if(rs.next()) {
            String sql3 = "INSERT INTO contractor (cvr, person_id) VALUES (2666,"+rs.getInt("id")+")";
            conn.createStatement().executeUpdate(sql3);
        }else{
            throw new SQLException();
        }

    } catch (SQLException e){
        e.printStackTrace();
    } finally {
        DBConnection.closeConnection();
    }
    return contractor;
}    

使用 JUnit 的测试会是什么样子?

【问题讨论】:

  • 我在询问 JUnit,我已经看到了这个问题,但它对我没有帮助。不过谢谢。
  • @Darshan 发布的链接应该会有所帮助。还可以了解 PreparedStatements。

标签: java sql testing junit


【解决方案1】:

好吧,必须使用 Junit 的方式是测试您的类的每个公共方法,根据实验成功或失败的数量使用尽可能多的不同参数化。

那么,每种测试方法都必须:

  • 选择一组合适的参数值。
  • (可选)将被测组件初始化为所需的初始状态。
  • 调用测试方法。
  • 检查返回结果是否与预期结果相同。
  • 清理已测试的组件,不要让已执行的测试有任何“污垢”。

在您的情况下,检查结果很困难,因为连接是由您的方法在本地管理的。更糟糕的是:数据会自动提交到连接中,每次测试时都会在数据库中留下脏记录。

为避免这种困难,只需进行一些先前的重构以简化测试开发:

  • 在您的类中重载方法create,使用包访问版本,该版本还接收一个连接,并将所有业务逻辑放在那里。
  • 公共重载应该只管理连接并调用新创建的重载。

然后,您可以安全地进行测试:

  • 如果您的类名为 MyClass,请在同一个包中创建一个 MyClassTest(通常在不同的源路径中,如 Maven 项目中的 src\test\java)。
  • 创建一个方法createSinglePerson(),它使用一组任意参数和一个连接(不是自动提交)调用create。之后,您必须检查 Person 表中是否比最初多一条记录,具有一组特定的值,以及 Contractor 表中的另一条记录具有特定的一组值。要比较每个值,您必须使用Asserts.assertEquals(expected, real)。最后(在 finally 子句中),回滚连接并关闭它。

您可以根据需要多次运行测试,知道它不会改变数据库状态。

(注意:参数cvr从未使用过。也许你是故意的,我不知道)。

示例

public class MyClassTest
{
    @Test
    public void createSinglePerson()
    {
        MyClass myClass=new MyClass();
        try(Connection connection=...)
        {
            try(Statement stCheck=connection.createStatement())
            {
                connection.setAutoCommit(false);

                // Initial cleanup:
                stCheck.executeUpdate("DELETE FROM person");
                stCheck.executeUpdate("DELETE FROM contractor");

                // Setting input parameters:
                String name="a";
                String address="b";
                String email="c@d.e";
                String phone="001";
                String city="f";
                int cvr=11;

                // Do the call:
                Contractor contractor=myClass.create(name, address, email, phone, city, cvr);

                // Javabean Checks: Check the javabean contains the expected values:
                assertEquals(name, contractor.getName());
                assertEquals(address, contractor.getAddress());
                ...

                // Database Checks:
                int personId;
                // Check the Person table contains one row with the expected values:
                try(ResultSet rs=stCheck.executeQuery("SELECT * FROM person"))
                {
                    assertTrue(rs.next());
                    personId=rs.getInt("id");
                    asssertEquals(name, rs.getString("name"));
                    asssertEquals(address, rs.getString("address"));
                    ...
                    assertFalse(rs.next());
                }

                // Check the Contractor table contains one row with the expected values:
                try(ResultSet rs=stCheck.executeQuery("SELECT * FROM contractor WHERE person_id="+personId))
                {
                    assertTrue(rs.next());
                    asssertEquals(2666, rs.getInt("cvr"));
                    ...
                    assertFalse(rs.next());
                }
            }
            finally
            {
                 // Undo the testing operations:
                 connection.rollback();
            }
        }
        catch (SQLException e)
        {
            fail(e.toString());
        }
    }
}

【讨论】:

  • 您好,非常感谢您的回复。我对java很陌生,你能告诉我一些真实的例子吗?我已经按照这个vogella.com/tutorials/JUnit/article.html 尝试过,但没有运气。
  • 我想问你。如果我按照您向我展示的那样对表进行初始清理,然后调用回滚,我会将旧文件保留在数据库中吗?
  • 你应该。但事实上,如果您的测试程序在正常结束前意外停止,则存在无法执行回滚,从而丢失数据的风险。为了防止这种灾难,值得使用单独的数据库进行测试。您可以使用内存数据库,例如 Derby 或 HSQLDB。
  • 或者,好吧,还有另一种选择:清理数据的目的是为了方便在Person表中查找新创建的记录。如果您修改了测试逻辑,您可以通过另一个标准(例如,插入最后一条记录)来查找它,而无需进行初始清理。
猜你喜欢
  • 2021-12-23
  • 1970-01-01
  • 2018-12-20
  • 2013-11-09
  • 1970-01-01
  • 2011-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多