需求:电话账单计费
对于电话账单来说,当春季和秋季标准时间与夏令时时间进行转换时会产生一个很有意思的问题: 春季,这种转换发生在(3月某个)星期日凌晨2:00点,这时要将时钟设置为凌晨3:00点;秋季, 转换通常在11月的第一个星期日,时钟要从2:59:59调回2:00:00。
请为长途电话服务函数开发计费类,使用等价类分析方法构建测试用例并使用Junit5测试。
采用如下计费规则计算通话费:
- 通话时间小于等于20分钟时,每分钟收费0.05美元,通话时间不足1分钟按1分钟计算。
- 通话时间大于20分钟时,收费1.00美元,外加超过20分钟的部分每分钟0.10美元;
- 不到1分钟按1分钟计算
假设:
- 通话计费时间从被叫方应答开始计算,到呼叫方挂机时结束;
- 通话时间的秒数向上进位到分钟;
- 没有超过30个小时的通话。
实验步骤:
1.任务前准备,配置好相关的文件,解决乱码问题;
2.分析题目,形成解题思路;
3.编写代码实现电话账单收费功能;
4.编写测试代码;
5. 采用边等价类分析方法设计测试用例,并采用Junit5 编写电话账单收费程序测试用例,并执行测试用例,记录测试结果;
6. 执行check任务和jacocoTestReport任务,生成静态代码检查报告和测试覆盖率报告,并根据checkstyle报告,改进代码,消除报告的问题。
7. 编写实验报告,实验报告的内容包括测试用例的测试结果、程序中存在的bug、以及这两种测试用例生成方法对于揭露程序的错误有什么异同点。
实现代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class BillTest {
public static void main(String[] args){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
System.out.println("请输入通话开始时间,例:20210404193600:");
String time1 = br.readLine();
System.out.println("请输入通话结束时间,例:20210404193600:");
String time2 = br.readLine();
try {
SimpleDateFormat format1 = new SimpleDateFormat("yyyyMMddHHmmss");
Date date1 = format1.parse(time1);
Date date2 = format1.parse(time2);
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
long phonetime = cal2.getTime().getTime() - cal1.getTime().getTime();
long minute;
if(phonetime>=0 && phonetime/1000<60 || phonetime%60000>0) //不到一分钟按一分钟计算
minute = phonetime/1000/60+1;
else
minute = phonetime/1000/60;
if(cal1.get(Calendar.MONTH) == Calendar.OCTOBER && cal1.get(Calendar.DATE) >= 25 && cal1.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
//开始时间在十月最后一个周日
if(cal1.get(Calendar.HOUR_OF_DAY)==2 && cal2.get(Calendar.HOUR_OF_DAY)==2 && cal2.get(Calendar.HOUR_OF_DAY)<3 && cal2.get(Calendar.MINUTE)<=cal1.get(Calendar.MINUTE)) {
//因为转换而出现通话时间为负的情况
minute+=60;
System.out.println("通话时长:"+minute);
System.out.println("通话账单:"+Money(minute));
}
else if(cal1.get(Calendar.HOUR_OF_DAY)<2 && cal2.get(Calendar.HOUR_OF_DAY)>=2) {
//开始时间是两点前,结束时间是两点后(经历第二次转换
System.out.println("通话时长:"+minute+"或"+(minute+60));
System.out.println("通话账单:"+Money(minute)+"或"+Money(minute+60));
}
else {
System.out.println("通话时长:"+minute);
System.out.println("通话账单:"+Money(minute));
}
}
else{
if(cal2.get(Calendar.MONTH) == Calendar.OCTOBER && cal2.get(Calendar.DATE) >= 25 && cal2.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
if(cal2.get(Calendar.HOUR_OF_DAY)>=2)
minute +=60;
}
else {
if((cal1.get(Calendar.MONTH) == Calendar.MARCH && cal1.get(Calendar.DATE) >= 25 && cal1.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)){
//开始时间在三月最后一个周日
if(cal1.get(Calendar.HOUR_OF_DAY)<2 && cal2.get(Calendar.HOUR_OF_DAY)>=3)
//开始时间在两点前,结束时间在三点后(经过了第一次转换
minute -=60;
}
else{//开始时间不在三月最后一个周日
if((cal2.get(Calendar.MONTH) == Calendar.MARCH && cal2.get(Calendar.DATE) >= 25 && cal2.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)){
//但是结束时间在(从前一天打到这一天
if(cal2.get(Calendar.HOUR_OF_DAY)>=3 )
minute -= 60;
}
}
}
System.out.println("通话时长:"+minute);
System.out.println("通话账单:"+Money(minute));
}
SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
String starttime = format2.format(date1);
System.out.println("通话开始时间:"+starttime);
String endtime = format2.format(date2);
System.out.println("通话结束时间:"+endtime);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static double Money(long minute) {
double money = 0;
if(minute>1200 || minute <=0){
System.out.println("通话时间输入错误,请重新输入。");
}else{
if(minute<=20)
money = minute*0.05;
else
money = 1+(minute-20)*0.1;
}
return money;
}
}
静态代码检查报告和测试覆盖率报告:
以下是按照等价类和边界值进行测试的数据
等价类测试:
(此通话时长为现实中通话时长,非结束时间-开始时间)
T1={通话时长≤0分钟}
T2={0分钟<通话时长<1分钟}
T3={1分钟≤通话时长≤20分钟}
T4={20分钟<通话时长≤1200分钟}
T5={通话时长>1200分钟}
S1={无时制转换}
S2={春时制与夏时制转换}
S3={夏时制与秋时制转换}