一、封装JDBC
1、executeUpdate方法
在添加、删除、修改的例子中,变化的数据只有SQL语句,其余的代码都是重复的,因此将重复的代码封装到一个方法中,变化的数据定义为方法参数。为此我们定义一个专门用于执行增删改的方法executeUpdate
,方法定义如下:
int executeUpdate(String sql,Object …values)
说明:
- 方法参数sql是要执行的
insert
、update
、delete
语句。 - 方法可变参数
values
是insert
、update
、delete
语句中占位符的值。 sql
和values
这两个参数从外界传入,即外界传入什么样的SQL语句,executeUpdate()
方法就执行什么样的SQL语句。- 返回值
int
表示SQL语句执行后影响的行数。
2、executeQuery方法
在查询的例子中,每次查询的SQL语句不同,为此我们定义一个专门用于执行查询的方法executeQuery
,方法定义如下:
ResultSet executeQuery(String sql,Object …values)
说明:
- 方法参数
sql
是要执行的select
语句。 - 方法可变参数
values
是SQL语句中占位符的值。 sql
和values
这两个参数从外界传入,即外界传入什么样的SQL,executeQuery
方法就 执行什么样的SQL语句。- 返回值
ResultSet
表示SQL语句执行查询后的查询结果集。
3、封装JDBC
在executeUpdate(String sql,Object …values)
方法和executeQuery(String sql, Object … values )
中都需要将values
的值赋给sql
语句中占位符?
,因此将这两个方法中为占位符?
赋值的代码抽象出来,定义为void setParameter(Object …values)
方法。
在executeUpdate(String sql,Object …values)
方法和executeQuery(String sql, Object … values)
中都需要连接数据库,关闭资源,因此将这两个方法中连接数据库的代码抽象出来,封装成getConnection()
方法,用于连接数据库,将关闭资源的代码抽象出来,封装成close()
方法,用于关闭资源。
Connection
对象、PreparedStatement
对象、ResultSet
对象、连接字符串定义为类的属性,由于这些属性不允许外界访问,因此将其定义为私有。
由于该类是专门执行SQL语句的类,因此我们称它为DBHelper
类。
实例:
import java.sql.*;
/**
* 数据库访问助手
*
* @author DingYi
* @date 2020/5/2 15:10
*/
public class DBHelper {
// 数据库连接
private Connection conn = null;
// 语句
private PreparedStatement ps = null;
// 结果集
private ResultSet rs = null;
// 连接URL
private static final String URL = "jdbc:mysql://localhost:3306/user_manager?useSSL=false&characterEncoding=utf8";
// 用户名
private static final String USER = "root";
// 密码
private static final String PASS = "root";
// 1.加载驱动
//加载驱动只需做一遍,故可以写在静态代码块中
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// 2. 获得连接
private void getConnection() throws SQLException {
if(conn == null || conn.isClosed()){
conn = DriverManager.getConnection(URL,USER,PASS);
}
}
// 为占位符?赋值
private void setParameter(Object ... values) throws SQLException {
if(values != null && values.length > 0){
for(int i = 0; i < values.length; i ++) {
ps.setObject(i + 1, values[i]);
}
}
}
/**
* 执行增删改的方法
* @param sql 要执行的sql语句
* @param values sql语句中?占位符的值
* @return 执行结果
* @throws SQLException sql异常
*/
public int executeUpdate(String sql, Object ... values) throws SQLException {
// 获得连接
getConnection();
// 创建语句
ps = conn.prepareStatement(sql);
// 为占位符?赋值
setParameter(values);
// 执行sql语句
return ps.executeUpdate();
}
/**
* 执行查询的sql语句
* @param sql 要执行的sql语句
* @param values sql语句中?占位符的值
* @return 查询结果
* @throws SQLException sql异常
*/
public ResultSet executeQuery(String sql, Object ... values) throws SQLException {
// 获得连接
getConnection();
// 创建语句
ps = conn.prepareStatement(sql);
// 为占位符?赋值
setParameter(values);
// 执行查询
rs = ps.executeQuery();
return rs;
}
// 6. 关闭资源
public void close() throws SQLException {
if(rs != null){
rs.close();
rs = null;
}
if(ps != null){
ps.close();
ps = null;
}
if(conn != null){
conn.close();
conn = null;
}
}
}
二、单元测试
1、单元测试
软件开发完成后,难免有bug存在(软件的缺陷称为bug),为了减少或避免bug,就必须对软件进行测试,发现bug后对bug进行修复,使得软件具有很好的稳定性和健壮性。
软件测试分为单元测试、模块测试、集成测试。通常模块测试和集成测试是测试工程师的职责,单元测试通常是开发工程师的职责。
单元测试(unit testing
),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,在Java中单元指一个类或者一个方法。通常使用JUnit单元测试工具对Java进行单元测试。
测试过程:
- 导入必要的包
单元测试的类和注解位于JUnit4框架的org.junit
包中,因此需要导入org.junit.*
。断言类Assert
的断言方法assertEquals
是静态方法,使用静态导入import static org.junit.Assert.*
后在单元测试类中可以直接使用Assert
类的静态方法进行断言。 - 测试类的定义
测试类CalculatorTest
是一个独立的类,没有显示继承任何父类。测试类的名字也可以任意命名,没有任何局限性。所以我们不能通过类的声明来判断它是不是一个测试类,它与普通类的区别在于它内部的方法的声明。 - 创建待测试的对象
要测试哪个类,首先就要创建一个该类的对象,如:
private static Calculator calculator = new Calculator();
在单元测试中,方法上标注了@Test
后,表明该方法是单元测试方法。除了@Test
注解外,还有一些重要的注解,其作用如下表所示:
注解 | 解释 | 示例 |
---|---|---|
@Test | 标注在方法上,表明这是一个测试方法,返回值必须为void ,而且不能有任何参数。 | @Test public void test() { } |
@Before | 在任何一个测试执行之前必须执行的代码 | @Before public void setUp() throws Exception { } |
@After | 在任何测试执行之后需要进行的收尾工作 | @After public void tearDown () throws Exception { } |
@BeforeClass | 1:针对所有测试 2:只在测试用例初始化时执行一次 3:每个测试类只能有一个方法被标注为 @BeforeClass 。4:该方法必须是 public 和static 的 | @BeforeClass public static void beforeClass() { } |
@AfterClass | 1:针对所有测试 2:只在测试用例执行结束时执行一次 3:每个测试类只能有一个方法被标注为 @AfterClass 4:该方法必须是 public 和static 的。 | @ AfterClass public static void AfterClass() { } |
@Ignore | 忽略的测试方法 |
一个JUnit4的单元测试用例执行顺序为:
注意:
- 需要的jar包
hamcrest-core-1.3.jar
junit-4.12.jar
- 在进行单元测试时,需要把相应地
Package
导入进来。最主要的Package
是org.junit.*
。 该包中包含了单元测试需要的绝大多数类;还需要导入import static org.junit.Assert.*
, 其中包含了许多断言,断言帮助我们判断测试的结果。
2、测试用例
测试用例(Test Case
)是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求。测试之前应先编写测试用例,根据测试用例进行测试,并记录测试结果。下表是测试用例:
说明:
- 桩模块:是指模拟被测试的模块所调用的模块
- 测试状态:P指通过 F指失败
实例:
创建功能类
/**
* 功能类
*
* @author DingYi
* @date 2020/5/2 21:50
*/
public class Calculator {
private static int result = 0; // 静态变量,用户存储计算结果
public void add (int n) {
result = result + n;
}
public void substract(int n) {
// result = result - n;
result = result - 1;
}
public void multiply(int n) {
// result = result * n;
// TODO 待开发
}
public void divide(int n) {
result = result / n;
}
public void clear() {
result = 0;
}
public int getResult() {
return result;
}
}
测试类:
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* 测试类
*
* @author DingYi
* @date 2020/5/2 21:57
*/
public class CalculatorTest {
private static Calculator calculator = new Calculator();
@Before
public void setUp() throws Exception {
calculator.clear();
}
@After
public void tearDown() throws Exception {
calculator.clear();
}
@Test
public void add() {
calculator.add(2);
calculator.add(3);
assertEquals(5, calculator.getResult());
}
@Test
public void substract() {
calculator.add(10);
calculator.substract(2);
assertEquals(8, calculator.getResult());
}
@Ignore("乘法还没有开发呢,暂时不需要测试")
@Test
public void multiply() {
}
@Test
public void divide() {
calculator.add(8);
calculator.divide(2);
assertEquals(4, calculator.getResult());
}
}