【问题标题】:Object is null from database unit test对象在数据库单元测试中为空
【发布时间】:2020-12-18 14:29:32
【问题描述】:

我有两个用 java 编写的函数,我正在尝试创建它们的单元测试。第一个功能是向数据库添加一个元素,第二个功能是通过它的 id 从数据库中获取元素。 我创建了他们的两个测试,第一个在数据库中正确插入。但是当我得到一个时,数据库似乎是空的!

enter code here
package com.example.service;

import com.example.model.City;
import org.junit.Test;

import java.sql.*;

public class DatabaseService {


public static int addCity(Connection conn, City city) {
    PreparedStatement pstmt = null;
    int i = -1;
    try {
        String sql = "INSERT INTO City " + "VALUES (?,?,?,?)";
        pstmt = conn.prepareStatement(sql);

            pstmt.setInt(1, city.getIdCity());
            pstmt.setString(2, city.getName());
            pstmt.setInt(3, city.getTouristNumber());
            pstmt.setString(4, city.getDescription());
            i = pstmt.executeUpdate();
            pstmt.close();


    } catch (SQLException se) {
        se.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (pstmt != null) pstmt.close();
        } catch (SQLException se2) {
        }
    }
    return i;
}


public static City getCity(Connection conn,int idCity) {
    PreparedStatement pstmt = null;
    City city = new City();
    try {

        String sql = "SELECT * FROM City where idCity=?";
        pstmt = conn.prepareStatement(sql);
        pstmt.setInt(1,idCity);
        ResultSet rs = pstmt.executeQuery();
        while (rs.next()) {
            city.setIdCity(rs.getInt("idCity"));
            city.setName(rs.getString("name"));
            city.setTouristNumber(rs.getInt("touristNumber"));
            city.setDescription(rs.getString("description"));
        }

        rs.close();
        pstmt.close();
    } catch (SQLException se) {
        se.printStackTrace();
    } finally {
        try {
            if (pstmt != null) pstmt.close();
        } catch (SQLException se2) {
        }
    }
    return  city;
}

}

对于连接:

enter code here
 package com.example.service;

  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.SQLException;
  import java.sql.Statement;

  public class DatabaseConnection {

private String USER;
private String PASS;
private String JDBC_DRIVER;
private String DB_URL;

public DatabaseConnection(String USER, String PASS, String JDBC_DRIVER, String DB_URL) {
    this.USER = USER;
    this.PASS = PASS;
    this.JDBC_DRIVER = JDBC_DRIVER;
    this.DB_URL = DB_URL;
}

public  Connection connect() {
    Connection conn = null;
    try {
        conn = DriverManager.getConnection(DB_URL, USER, PASS);
        Class.forName(JDBC_DRIVER);
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return conn;
}

public  void disconnect(Connection conn ) {
    try {
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

public void createDb(Connection conn) {
    Statement stmt = null;
    try {
        stmt = conn.createStatement();
        String sql =  "CREATE TABLE   City " +
                "(idCity INTEGER not NULL, " +
                " name VARCHAR(255), " +
                " touristNumber INTEGER, " +
                " description VARCHAR(255), " +
                " PRIMARY KEY ( idCity ))";
        stmt.executeUpdate(sql);
        stmt.close();
    } catch(SQLException se) {
        se.printStackTrace();
    } catch(Exception e) {
        e.printStackTrace();
    } finally {
        try{
            if(stmt!=null) stmt.close();
        } catch(SQLException se2) {
        }
    }
}

}

对于单元测试:

enter code here
 package com.example.service;

import com.example.model.City;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

 import java.sql.Connection;

import static org.junit.Assert.*;

public class DatabaseServiceTest {
City city;

Connection conn;
DatabaseConnection datab;
@Before
public void init(){
    datab= new DatabaseConnection("sa","","org.h2.Driver","jdbc:h2:mem:test") ;
   conn = datab.connect();
   datab.createDb(conn);
    city = new City(1,"Alger",123,"capital");



}
@Test
public void addCity() {

    assertEquals(1,new DatabaseService().addCity(conn, city));

}

@Test
public void getCity() {

    assertEquals(city.getIdCity(),new DatabaseService().getCity(conn, 1).getIdCity());
 /*   assertEquals(city.getTouristNumber(),new DatabaseService().getCity(conn, 1).getTouristNumber());
    assertEquals(city.getName(),new DatabaseService().getCity(conn, 1).getName());
    assertEquals(city.getDescription(),new DatabaseService().getCity(conn, 1).getDescription());*/
}

}

对于调试结果,我得到了这个:(第二个得到:)

enter code here
 Connected to the target VM, address: '127.0.0.1:3543', transport: 'socket'
 Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot 
 loader classes because bootstrap classpath has been appended

 java.lang.AssertionError: 
 Expected :1
 Actual   :0
at org.junit.Assert.fail(Assert.java:93)
at org.junit.Assert.failNotEquals(Assert.java:647)
at org.junit.Assert.assertEquals(Assert.java:128)
at org.junit.Assert.assertEquals(Assert.java:472)
at org.junit.Assert.assertEquals(Assert.java:456)
at com.example.service.DatabaseServiceTest.getCity(DatabaseServiceTest.java:37)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

Disconnected from the target VM, address: '127.0.0.1:3543', transport: 'socket'

 Process finished with exit code -1

【问题讨论】:

  • 你试过调试测试吗?
  • 是的,我通过添加第二个(getCities)的调试来编辑代码

标签: java unit-testing junit


【解决方案1】:

您可能会发现使用 Mockito 模拟数据库连接而不是使用内存数据库很有趣,原因有两个:

  1. 内存中的数据库可能会在并行运行测试时引入问题
  2. 由于不是同一个数据库,可能存在内存版本中不存在的特殊 SQL 功能或关键字。

看看这个,它可以帮助您了解如何使用模拟连接测试 DatabaseService: How to use mockito for testing Database connection

【讨论】:

  • 您好,感谢您的回答。对于内存中的数据库,我必须使用它,因为我有一个这样的练习,但你能解释一下我理解的第二个原因是它可以在不同的执行后更改数据库吗?
  • ohhhh 明白了,#2 我的意思是,有时您想使用无法在您正在使用的内存版本中实现的特定 db 功能或关键字(不是标准 sql)。但如果这是为了练习,那很可能没问题。
猜你喜欢
  • 2019-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多