【问题标题】:JUnit 5 - JDBC statements testingJUnit 5 - JDBC 语句测试
【发布时间】:2017-06-19 09:05:28
【问题描述】:

我已经开始学习单元测试了。我正在使用 JUnit 5,我想测试将一些数据插入数据库的方法(使用 JDBC)。这是我的代码:

Datasource.java

import java.sql.*;

public class Datasource {

    public static final String CONNECTION = "jdbc:mysql://127.0.0.1:3306/java";

    private Connection connection;

    public boolean open() {
        try {
            connection = DriverManager.getConnection(CONNECTION, "root", "");
            return true;

        } catch (SQLException e) {
            System.out.println(e.getMessage());
            return false;
        }
    }

    public boolean insertTable() {
        try {
            String query = "INSERT INTO artists(name) VALUES(?)";
            PreparedStatement stmt = connection.prepareStatement(query);
            stmt.setString(1, "Test");
            int result = stmt.executeUpdate();

            if (result == 1) return true;
            return false;

        } catch (SQLException e) {
            System.out.println(e.getMessage());
            return false;
        }
    }

}

DatasourceTest.java

import static org.junit.jupiter.api.Assertions.*;

class DatasourceTest {

    private Datasource datasource;

    @org.junit.jupiter.api.BeforeEach
    void setUp() {
        datasource = new Datasource();

        if (!datasource.open()) {
            System.exit(-1);
        }
    }

    @org.junit.jupiter.api.Test
    void insertTable() {

        assertTrue(datasource.insertTable());

    }

}

它工作正常,但它实际上在我的数据库中插入了一条记录,但我想做的是模拟它。是否可以仅使用 JUnit 来实现?如果没有,我需要什么?一个简单的实现将不胜感激。

编辑

我发现了一个名为 Mockito 的工具,这是我需要的吗?如果是这样,谁能告诉我如何部署我的方法 insertTable() 的简单测试?

【问题讨论】:

  • 不,仅使用 JUnit 是不可能的,因为您正在测试与其他系统(在本例中为数据库)的集成。这些类型的测试通常不是单元测试,它们确实将数据发送到外部系统。
  • @M.Prokhorov 您可以测试正确的插入语句。你可以看看 PowerMockito。您可以在哪里模拟由静态 DriverManager 创建的 Connection 并使用正确的插入语句验证 connection.prepareStatement(query) 调用
  • @kism3t 我找不到任何合理的教程,你能推荐一些东西吗,如何将它与 JUnit 5 和 JDBC 一起使用?
  • @kism3t,但这仍然无法仅使用 JUnit。我还发现编写测试来验证是否将硬编码的字符串常量传递给方法很愚蠢。
  • @BociucH,另外,您可能真的想重新考虑 System.exit(-1) 声明。通过使用它,你会弄乱 JUnit 的错误报告系统。

标签: java jdbc junit junit5


【解决方案1】:

这就是我使用 mockito 测试 insetTable 方法所做的

import static org.junit.Assert.*;    
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;    
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;    

@RunWith(MockitoJUnitRunner.class)
public class DatasourceTest {

    @InjectMocks
    Datasource datasource;
    @Mock
    Connection connection;
    @Mock
    PreparedStatement stmt;    
    @Before
    public void setUp() throws SQLException {
        when(connection.prepareStatement(eq("INSERT INTO artists(name) VALUES(?)"))).thenReturn(stmt);
        when(stmt.executeUpdate()).thenReturn(1);

    }

    @Test
    public void testInsertTable() {
        assertTrue(datasource.insertTable());

    }    
}

【讨论】:

  • Datasource 的导入是什么?
  • Datasource 正在测试中。
【解决方案2】:

您可以将DbUnit framework 与 H2 或 HSQL 内存数据库一起使用。

您将打开到内存数据库的真实连接,您可以使用 DataSets 检查记录是否保存

【讨论】:

    【解决方案3】:

    所以如果在 1.6.5 版本中使用 PowerMockito,我将按以下方式测试您的代码

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    
    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.Mock;
    import org.mockito.Mockito;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest({ Datasource.class, DriverManager.class, Connection.class })
    public class DatasourceTest {
    
        @Mock
        Connection con;
    
        @Mock
        PreparedStatement ps;
    
        @Test
        public void insertTableTest() throws Exception {
    
            PowerMockito.mockStatic(DriverManager.class);
            PowerMockito.when(DriverManager.getConnection(
                    Mockito.eq("jdbc:mysql://127.0.0.1:3306/java"),
                    Mockito.eq("root"),
                    Mockito.eq(""))).thenReturn(con);
    
            Datasource ds = Mockito.mock(Datasource.class);
            PowerMockito.doCallRealMethod().when(ds).open();
            PowerMockito.doCallRealMethod().when(ds).insertTable();
    
            boolean result = ds.open();
            Assert.assertTrue(result);
    
            Mockito.when(con.prepareStatement(Mockito.eq("INSERT INTO artists(name) VALUES(?)"))).thenReturn(ps);
            Mockito.when(ps.executeUpdate()).thenReturn(1);
    
            result = ds.insertTable();
            Assert.assertTrue(result);
    
            Mockito.verify(ps).setString(Mockito.eq(1), Mockito.eq("Test"));
            Mockito.verify(ps).executeUpdate();
            Mockito.verify(con).prepareStatement(Mockito.eq("INSERT INTO artists(name) VALUES(?)"));
    
        }
    }
    

    希望这会有所帮助。

    【讨论】:

    • 这正是我所需要的,非常感谢!有没有办法只使用 Mockito 而不是 PowerMockito 来做同样的事情?
    • 不,不是你的代码。如果您使用的是 spring 和 hibernate,那将是可能的。
    猜你喜欢
    • 2016-12-16
    • 2020-04-07
    • 1970-01-01
    • 2023-03-30
    • 2022-08-20
    • 1970-01-01
    • 2019-06-08
    • 2018-07-29
    • 2021-01-06
    相关资源
    最近更新 更多