目录
一、简介
本博客对结对编程队友高义林同学的个人项目进行分析测试,使用语言为Java。需求如下图所示:
二、测试与分析
1.功能测试
1.登录功能测试
分析:登录时输入错误账密、错误密码、空的账密均不可成功登录,可以满足普通的登陆需求,且提示到位,登录成功后出现准备生成题目提示,符合要求。
分析:可以正常退出登录,退出之后可以再次登录,满足日常需要。
2.生成题目功能与切换难度功能测试
分析:输入10~30之间的数字可以正常生成试卷,输入不符合要求的数字会出现错误提示并返回生成界面,符合需求。试卷文件名以规定时间格式命名,每道题目之间以空行隔开,以题号开头,整洁美观,符合需求。
分析:切换时输入错误会触发提示信息,输入正确后成功切换,生成的题目难度也切换完毕。
2.代码分析
1.项目结构
本项目共有7个类,包含2个抽象类Question和Check,其余5个类分别是CheckUnit,FileProduct,Main,QuestionUnit,User。其中QuestionUnit类继承Question类,CheckUnit类继承Check类,实现抽象方法。
CheckUnit类 |
实现抽象类Check功能,完成查重操作 |
FileProduct类 |
生成试卷的文件操作 |
Main类 |
初始化账户,实现操作界面 |
QuestionUnit类 |
生成题目 |
User类 |
账户类型 |
2.代码分析
- Main.java
-
import java.util.ArrayList; import java.util.Scanner; public class Main { public static boolean flag; public static ArrayList<User> userList; public static User curUser; public static void initArray() { userList = new ArrayList<>(); userList.add(new User("小学", "张三1", "123")); userList.add(new User("小学", "张三2", "123")); userList.add(new User("小学", "张三3", "123")); userList.add(new User("初中", "李四1", "123")); userList.add(new User("初中", "李四2", "123")); userList.add(new User("初中", "李四3", "123")); userList.add(new User("高中", "王五1", "123")); userList.add(new User("高中", "王五2", "123")); userList.add(new User("高中", "王五3", "123")); } public static void mainMenu() { System.out.println("请输入用户名和密码,两者之间用空格隔开,或输入exit退出"); while (!flag) { String temp; Scanner scanner = new Scanner(System.in); temp = scanner.nextLine(); if (temp.equals("exit")) { flag = true; System.out.println("系统退出"); continue; } String[] tempUser = temp.split(" "); if (tempUser.length != 2) { System.out.println("请输入正确的用户名、密码”,重新输入用户名、密码"); } else { for (User user : userList) { if (user.getName().equals(tempUser[0]) && user.getPassword().equals(tempUser[1])) { curUser.setName(user.getName()); curUser.setPassword(user.getPassword()); curUser.setType(user.getType()); flag = true; break; } } if (!flag) System.out.println("请输入正确的用户名、密码”,重新输入用户名、密码"); else { testProductMenu(curUser); flag = false; curUser = new User(); System.out.println("请输入用户名和密码,两者之间用空格隔开,或输入exit退出"); } } } } public static void testProductMenu(User curUser) { boolean flag = true; while (flag) { System.out.println("准备生成" + curUser.getType() + "数学题目,请输入生成题目数量"); System.out.println("题目数量在10~30之间,或输入-1退出登录,或输入”切换为xx“更换出卷类型"); Scanner scanner = new Scanner(System.in); String temp = scanner.nextLine(); if (temp.length() > 3 && temp.startsWith("切换为")) { temp = temp.substring(3); switch (temp) { case "小学" -> curUser.setType("小学"); case "初中" -> curUser.setType("初中"); case "高中" -> curUser.setType("高中"); default -> System.out.println("请输入小学、初中和高中三个选项中的一个"); } } else { int num; try { num = Integer.parseInt(temp); if (num == -1) { flag = false; System.out.println("退出登录"); } else if (num >= 10 && num <= 30) { FileProduct.createTest(curUser, num); } else System.out.println("输入数量不在10~30之间"); } catch (NumberFormatException exc) { System.out.println("输入格式错误"); } } } } public static void main(String[] args) { flag = false; curUser = new User(); initArray(); mainMenu(); } }
分析:Main类中实现了整个界面操作,flag变量标记是否切换界面。首先创建当前用户,初始化用户列表,进入主菜单,随后进行菜单操作。
- FileProduct.java
-
import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; public class FileProduct { public static CheckUnit checkUnit = new CheckUnit(); public static QuestionUnit questionUnit = new QuestionUnit(); public static void createTest(User curUser, int num) { File file = createFile(curUser); File checkFile = checkUnit.getDir(); FileWriter fileWriter; FileWriter fileWriter1; try { fileWriter = new FileWriter(file, true); fileWriter1 = new FileWriter(checkFile, true); } catch (IOException e) { throw new RuntimeException(e); } String tempQuestion; for (int i = 0; i < num; i++) { tempQuestion = formatQuestion(curUser, i, fileWriter1); try { fileWriter.write(tempQuestion + "\n\n"); } catch (IOException e) { throw new RuntimeException(e); } } try { fileWriter.close(); fileWriter1.close(); } catch (IOException e) { throw new RuntimeException(e); } System.out.println("试卷创建成功"); } public static File createFile(User curUser) { Date date = new Date(); String time = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(date); String path = System.getProperty("user.dir") + "\\user\\" + curUser.getName() + "\\" + curUser.getType(); String filename = time + ".txt"; File file = new File(path + "\\" + filename); File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } dir = new File(path + "\\check.txt"); checkUnit.setFile(file); checkUnit.setDir(dir); return file; } public static String formatQuestion(User curUser, int i, FileWriter fileWriter) { boolean flag; String tempQuestion = ""; flag = false; while (!flag) { int typeNum = 0; if (curUser.getType().equals("小学")) typeNum = 1; else if (curUser.getType().equals("初中")) typeNum = 2; else if (curUser.getType().equals("高中")) typeNum = 3; tempQuestion = questionUnit.createQuestion(typeNum) + "="; flag = checkUnit.checkQuestion(tempQuestion); if (flag) { try { fileWriter.write(checkUnit.hashCode(tempQuestion) + "\n"); } catch (IOException e) { throw new RuntimeException(e); } } tempQuestion = i + 1 + ". " + tempQuestion; } return tempQuestion; } }
分析:此类主要由三个方法组成,完成对文件的操作。首先createFile方法准备好文件路径,formatQuestion方法调用questionUnit.createQuestion方法和checkUnit.checkQuestion方法实现单个题目的生成和查重,最后上述两种方法被createTest方法调用生成整张试卷。
- User.java
-
public class User { String name; String type; String password; public User() {} public User(String type, String name, String password) { this.type = type; this.name = name; this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
分析:实现了User类的三个属性的构造和调用。
- Check.java
-
import java.io.File; public abstract class Check { static File file; static File dir; public abstract File getFile(); public abstract void setFile(File file); public abstract File getDir(); public abstract void setDir(File dir); public abstract Boolean checkQuestion(String question); public abstract String hashCode(String question); }
分析:实现了抽象方法的定义。
- Question.java
-
public abstract class Question { public static final String[] operator0 = {"+", "-", "*", "/"}; public static final String[] operator1 = {"sqrt", "^2"}; public static final String[] operator2 = {"sin", "cos", "tan"}; public abstract String createQuestion(int typeNum); }
分析:实现了抽象方法的定义。
- CheckUnit.java
-
import java.io.*; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class CheckUnit extends Check { @Override public File getFile() { return file; } @Override public void setFile(File file) { Check.file = file; } @Override public File getDir() { return dir; } @Override public void setDir(File dir) { Check.dir = dir; } @Override public Boolean checkQuestion(String question) { FileReader fileReader; try { fileReader = new FileReader(dir); } catch (FileNotFoundException e) { throw new RuntimeException(e); } BufferedReader bufferedReader = new BufferedReader(fileReader); question = hashCode(question); try { String temp = bufferedReader.readLine(); while (temp != null) { if (temp.equals(question)) { System.out.println("A question is already in the database"); return false; } temp = bufferedReader.readLine(); } } catch (IOException e) { throw new RuntimeException(e); } return true; } @Override public String hashCode(String question) { MessageDigest md; try { md = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } byte[] hashInBytes = md.digest(question.getBytes()); StringBuilder sb = new StringBuilder(); for (byte b : hashInBytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } }
分析:继承抽象类,实现抽象方法。主要功能由checkQuestion方法和hashCode方法实现。其中checkQuestion方法逐条检查历史记录文件,寻找重复题目,hashCode方法将题目转换为哈希码实现加密,最后查重比较哈希码是否相同。
- QuestionUnit.java
-
import java.util.Random; public class QuestionUnit extends Question { @Override public String createQuestion(int typeNum) { Random rand = new Random(); int num = rand.nextInt(5) + 1; if (typeNum == 1) { num = rand.nextInt(4) + 2; } String[] numberList = new String[num]; for (int i = 0; i < num; i++) { numberList[i] = String.valueOf(rand.nextInt(100) + 1); } String Question = ""; int pos = rand.nextInt(num) + 1, caseNum; for (int i = 1; i <= num; i++) { if (typeNum == 2 && i == pos) { caseNum = rand.nextInt(2) + 1; if (caseNum == 1) Question += operator1[0] + "(" + numberList[i - 1] + ")"; else if (caseNum == 2) Question += numberList[i - 1] + operator1[1]; } else if (typeNum == 3 && i == pos) { caseNum = rand.nextInt(3) + 1; if (caseNum == 1) Question += operator2[0] + "(" + numberList[i - 1] + ")"; else if (caseNum == 2) Question += operator2[1] + "(" + numberList[i - 1] + ")"; else if (caseNum == 3) Question += operator2[2] + "(" + numberList[i - 1] + ")"; } else Question += numberList[i - 1]; if (i != num) Question += operator0[rand.nextInt(operator0.length)]; } return Question; } }
分析:此类继承Question类,实现抽象方法createQuestion。其主要思想在于先确定生成操作数的数量,然后选定一个操作数,根据不同难度对其进行不同操作。例如生成了五个操作数12345,选定4进行高中难度转换,就可能变成123sqrt(4)5,最后用随机符号依次拼接即可。但是这样只会对一个操作数进行难度转换。
三、总结
此项目基本完成了所给需求,测试下来也没有bug,使用体验良好,稍加修改即可成为一个实用的小程序。此外,还有许多地方可以进行功能升级,例如将账户信息保存到本地或者云端,实现初高中难度的多个操作数难度转换,在生成试卷时等待1秒避免题目数据重复写入等功能。
标签:curUser,Java,String,互评,小初,User,File,new,public From: https://www.cnblogs.com/H-v-H/p/17715848.html