老师新作“带着ChatGPT玩转软件开发”将于今年底明年初出版
2.2 ChatGPT生成用户注册的单元测试代码
产品的单元测试主要针对后端代码进行验证。由于后端代码是基于Java实现的,因此将使用JUnit5框架+mockito进行测试。目前,有以下四个后端Java文件。
•ValidateUser.java。
•UserRepository.java。
•User.java。
•Util.java。
接下来,为这四个Java文件让ChatGPT给出相应的单元测试用例。
2.2.1申请ChatGPT生成用户注册的单元测试代码
提示词
请对下面Java代码生成JUnit5的单元测试用例。
1.ValidateUser.java
参看代码2-10 ValidateUser.java
2.UserRepository.java
参看代码2-15 UserRepository.java
3.User.java
参看代码2-6 User.java
4.Util.java
参看代码2-12 Util.java
2.2.2 ChatGPT生成用户注册的单元测试代码回复
ChatGPT回答
针对上述的Java文件,可以为每个类编写一些单元测试用例。单元测试可以帮助确保代码的功能和逻辑是否正常。下面是针对ValidateUser.java,UserRepository.java,User.java,和Util.java的一些单元测试示例。
1.ValidateUserTest.java
ValidateUserTest.java测试ValidateUser.java。
1)测试boolean isHash(Str)方法
代码2-17 ValidateUserTest.java
package ebusiness;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
public class ValidateUserTest{
private ValidateUser validator=new ValidateUser();
//测试boolean isHash(str)方法,当参数str是一个经过SHA256散列处理的字符串时的行为。
@Test
public void testIsHash_SHA256(){
Assertions.assertTrue(validator.isHash("d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2"));
}
//测试boolean isHash(str)方法,当参数str不是一个有效的散列字符串时的行为。
@Test
public void testIsHash_InvalidHash(){
Assertions.assertFalse(validator.isHash("12345"));
}
//测试boolean isHash(str)方法,当参数str为null时的行为。
@Test
public void testIsHash_NullInput(){
Assertions.assertFalse(validator.isHash(null));
}
}2)测试String validate(user)方法
代码2-18 ValidateUserTest.java
…
//测试validate(user)方法在用户数据正确无误时的行为。
@Test
public void testValidate_Success(){
User user=new User();
user.setUsername("validUser");
user.setPhone("13812345678");
user.setEmail("validuser@example.com");
user.setPassword("d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2");
Assertions.assertEquals("验证成功",validator.validate(user));
}
//测试validate(user),用户的账号格式不正确的情况。
@Test
public void testValidate_InvalidUsername(){
User user=new User();
user.setUsername("invalidUser@123");
user.setPhone("13812345678");
user.setEmail("validuser@example.com");
user.setPassword("d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2");
Assertions.assertEquals("账号必须是5-20位字母或数字",validator.validate(user));
}
//测试validate(user),手机号码格式不正确的情况
@Test
public void testValidate_InvalidPhone(){
User user=new User();
user.setUsername("validUser");
user.setPhone("123");
user.setEmail("validuser@example.com");
user.setPassword("d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2");
Assertions.assertEquals("手机号必须符合中国手机号码格式",validator.validate(user));
}
//测试validate(user),电子邮件格式不正确的情况。
@Test
public void testValidate_InvalidEmail(){
User user=new User();
user.setUsername("validUser");
user.setPhone("13812345678");
user.setEmail("invalidemail.com");
user.setPassword("d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2");
Assertions.assertEquals("Email格式不正确",validator.validate(user));
}
//测试validate(user),用户密码未经过SHA256散列的情况。
@Test
public void testValidate_InvalidPasswordHash(){
User user=new User();
user.setUsername("validUser");
user.setPhone("13812345678");
user.setEmail("validuser@example.com");
user.setPassword("plainpassword");
Assertions.assertEquals("密码应该哈希进行存储",validator.validate(user));
}2.UserRepositoryTest.java
UserRepositoryTest.java测试UserRepository.java。
代码2-19 UserRepositoryTest.java
package ebusiness;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class UserRepositoryTest{
//测试注册用户时,该账号已注册过的情形。
@Test
public void testInsert_UserExists(){
try{
Connection conn=mysql.connect();
User user=new User();
user.setUsername("existingUser");
user.setPassword("password");
user.setPhone("13812345678");
user.setEmail("existinguser@example.com");
String result=mysql.insert(conn,user);
Assertions.assertEquals("username",result);//假设该账号已经存在
mysql.disconnect(conn);
}catch(SQLException e){
System.out.println(e.getMessage());
fail("Insert failed");
}
}
//测试注册用户成功的情形。
@Test
public void testInsert_Success(){
try{
Connection conn=mysql.connect();
User user=new User();
user.setUsername("newUser");
user.setPassword("password");
user.setPhone("13812345678");
user.setEmail("newuser@example.com");
String result=mysql.insert(conn,user);
Assertions.assertEquals("注册用户的账号必须唯一",result);//假设插入成功返回受影响的行数
mysql.disconnect(conn);
}catch(SQLException e){
System.out.println(e.getMessage());
fail("Insert failed");
}
}
}注解。
•代码注释“假设该账号已存在”ChatGPT原文:Assuming this username already exists。
•代码注释“假设插入成功返回受影响的行数”ChatGPT原文:Assuming insert success returns affected rows count。
考虑本书读者主要是中国人,而ChatGPT是国外的LLM工具,它生成的注释代码均为英文,作者对于比较复杂的注释,都译成中文,不再显示英文原文。
3.UserTest.java
UserTest.java类测试Util.java。
对于User.java,我们不需要编写单元测试,因为它只是一个POJO类,包含基本的getter()和setter()方法。这些方法的功能是标准的,可以通过其他类的测试间接验证其功能。
4.myUtilTest.java
myUtilTest.java类测试Util.java。
建立文件myUtilTest.java,添加测试方法void testGenerateRandomString_Length()方法和void testGenerateRandomString_ValidCharacters()方法,分别测试生成的随机字符串的长度是否符合预期的情形和生成的随机字符串是否包含指定的有效字符的情形。
代码2-20 myUtilTest.java
package ebusiness;
import static org.junit.Assert.*;
import org.junit.Test;
public class myUtilTest{
@Test
//测试生成的随机字符串的长度是否符合预期的情形。
public void testGenerateRandomString_Length(){
String randomString=Util.generateRandomString(10);
assertNotNull(randomString);
Assertions.assertEquals(10,randomString.length());
}
//测试生成的随机字符串是否包含指定的有效字符的情形。
@Test
public void testGenerateRandomString_ValidCharacters(){
String randomString=Util.generateRandomString(20);
Assertions.assertTrue(randomString.matches("[A-Za-z0-9]{20}"));
}
}总结
•ValidateUser类中的方法是否按照预期工作,包括哈希验证和用户信息验证。
•UserRepository类的数据库连接、断开连接以及用户插入功能是否正常。
•Util类的随机字符串生成功能是否正常。
这些测试用例确保了基础功能的正确性,并且涵盖了典型的成功和失败路径。在实际开发中,还可以根据需求扩展更多的测试场景。
2.2.3运行单元测试代码
1.运行ValidateUserTest.java
运行ValidateUserTest.java测试通过。
2.运行UserRepositoryTest.java
在运行UserRepositoryTest.java时,void testInsert_UserExists()和void testInsert_Success()测试用例失败。经过分析,原因是测试完成后未删除测试数据,导致产生垃圾数据,进而影响后续测试用例的运行结果。
在myUtilTest.java文件,添加方法boolean deleteUser(Connection conn,User user)方法。
代码2-21 myUtilTest.java
package ebusiness;
import static org.junit.jupiter.api.Assertions.fail;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
…
//从数据库中删除指定的用户,用于在测试后清除测试数据。
public boolean deleteUser(Connection conn,User user){
try{
String deleteString="DELETE from user where username=?";
PreparedStatement ps=conn.prepareStatement(deleteString);
ps.setString(1,user.getUsername());
int affectedRows=ps.executeUpdate();
if(affectedRows==1){
return true;
}else{
return false;
}
}catch(SQLException e){
System.out.println(e.getMessage());
fail("delete failed");
}
return false;
}接着,修改void testInsert_UserExists()和void testInsert_Success()方法,具体修改见代码中的粗体部分。
代码2-22 UserRepositoryTest.java
@Test
//测试插入用户时,已存在同名用户的情况。
public void testInsert_UserExists(){
try{
Connection conn=mysql.connect();
User user=new User();
user.setUsername("existingUser");
user.setPassword("password");
user.setPhone("13812345678");
user.setEmail("existinguser@example.com");
String result=mysql.insert(conn,user);
Assertions.assertEquals("1",result);
result=mysql.insert(conn,user);
myUtilTest ut=new myUtilTest()
if(!ut.deleteUser(user,conn)){
System.out.print("删除失败");
}
mysql.disconnect(conn);
Assertions.assertEquals("username",result);
}catch(SQLException e){
System.out.println(e.getMessage());
fail("插入失败");
}
}
@Test
//测试成功插入用户的情况。
public void testInsert_Success(){
try{
Connection conn=mysql.connect();
User user=new User();
user.setUsername("newUser");
user.setPassword("password");
user.setPhone("13812345678");
user.setEmail("newuser@example.com");
String result=mysql.insert(conn,user);
myUtilTest ut=new myUtilTest()
if(!ut.deleteUser(user,conn)){
System.out.print("删除失败");
}
mysql.disconnect(conn);
Assertions.assertEquals("注册用户的账号必须唯一",result);
}catch(SQLException e){
System.out.println(e.getMessage());
fail("Insert failed");
}
}再次运行测试,所有用例通过。
注意:通过ChatGPT生成的测试脚本可能存在考虑不周全的情况,脚本生成后,请务必进行人工核对,并根据需要进行修正。 |
|---|
3.运行myUtilTest.java
所有测试用例均已通过。
顾翔凡言:人工智能未来的发展瓶颈在于对知识的更新。唯一不变的是变化,知识发生了变化,人工智能软件能否及时跟进变化,可能阻碍人工智能的使用。