• 计算某天的下一天:黑盒测试之等价类划分+JUnit参数化测试


    题目要求

    测试以下程序:该程序有三个输入变量month、day、year(month、day和year均为整数值,并且满足:1≤month≤12、1≤day≤31和1900≤year≤2050),分别作为输入日期的月份、日、年份,通过程序可以输出该输入日期在日历上隔一天的日期。例如,输入为2004年11月30日,则该程序的输出为2004年12月1日。

    1. 划分等价类,按照等价类划分法设计测试用例;
    2. 编写getNextDate函数;
    3. 掌握Junit4的用法,使用Junit4测试getNextDate函数。

    等价类表

    假设输入格式为year,month,day,且三个输入变量year、month和day均被输入。

    year要区分闰年和平年,其中闰年还可以分为世纪闰年和普通闰年,且year要属于[1900,2050]。

    month要根据该月有几天来进行区分,并且需要考虑是否向year进位,且month要属于[1,12]。

    day要根据月份来判断天数是否合法,并且需要考虑是否向month进位,且day要属于[1,31]。

    等价类划分如下。

    等价类划分表.jpg

    测试用例

    有效等价类测试用例

    共有5个有效等价类测试用例。

    测试数据 期望结果 覆盖范围
    2004/12/25 2004/12/26 2,10,14
    2001/2/28 2001/3/1 3,7,15
    2000/2/29 2000/3/1 1,7,16
    2001/4/30 2001/5/1 3,8,17
    2001/5/31 2001/6/1 3,9,18

    无效等价类测试用例

    共有12个有效等价类测试用例。

    测试数据 期望结果 覆盖范围
    1899/6/1 year非法 4
    2051/6/1 year非法 5
    a/6/1 year非法 6
    1999/0/1 month非法 11
    1999/13/1 month非法 12
    1999/a/1 month非法 13
    1999/1/0 day非法 19
    1999/1/32 day非法 20
    1999/1/a day非法 21
    2001/2/29 day非法 22
    2000/2/30 day非法 23
    2001/4/31 day非法 24

    源代码

    项目结构如下图所示

    项目结构.jpg

    DateUtil.java

    package com.company;
    
    public class DateUtil {
        // 有31天的月份
        private static int[] monthOfThirtyOne = new int[]{1,3,5,7,8,10,12};
        // 有30天的月份
        private static int[] monthOfThirty = new int[]{4,6,9,11};
        // 年月日
        private int year;
        private int month;
        private int day;
    
        // 最终实现的功能,输入是一个“年/月/日”格式的字符串;
        // 如果函数运行成功,输出则是相同格式的下一天,否则是错误信息
        public String getNextDate(String dateStr){
            String updateResult = this.updateDate(dateStr);
            // 如果输入合法
            if (updateResult.equals("success")){
                String checkResult = this.checkDate();
                // 如果输入合法
                if (checkResult.equals("valid")){
                    // 计算明天的日期
                    return this.calcNextDate();
                }
                return checkResult;
            }
            return updateResult;
        }
    
        // 根据输入字符串转换并更新年月日
        private String updateDate(String dateStr){
            // 获取年月日
            String[] numbers = dateStr.split("/");
            try{
                this.year = Integer.parseInt(numbers[0]);
            }catch (NumberFormatException e){
                return "year非法";
            }
            try{
                this.month = Integer.parseInt(numbers[1]);
            }catch (NumberFormatException e){
                return "month非法";
            }
            try{
                this.day = Integer.parseInt(numbers[2]);
            }catch (NumberFormatException e){
                return "day非法";
            }
            return "success";
        }
    
        // 检查日期是否合法
        private String checkDate(){
            String valid = "valid";
            String yearInvalid = "year非法";
            String monthInvalid = "month非法";
            String dayInvalid = "day非法";
            // year合法
            if (year>=1900&&year<=2050){
                // month合法
                if (month>=1&&month<=12){
                    // day小于1
                    if (day<=0){
                        return dayInvalid;
                    }
                    // 至此能保证day大于0
    
                    // 是2月
                    if (month==2){
                        // 闰年
                        if (yearIsLeap(year)){
                            // 1-29
                            if (day<=29){
                                return valid;
                            }else{
                                return dayInvalid;
                            }
                        }
                        // 平年2月
                        else{
                            // 1-28
                            if (day<=28){
                                return valid;
                            }else{
                                return dayInvalid;
                            }
                        }
                    }
    
                    // 至此能保证不是2月
    
                    // 是否为31天的月
                    for(int i=0;i<7;++i){
                        if (month==monthOfThirtyOne[i]){
                            // 1-31
                            if (day<=31){
                                return valid;
                            }else{
                                return dayInvalid;
                            }
                        }
                    }
    
                    // 至此能保证不是2月和31天的月
    
                    // 是否为30天的月
                    for(int i=0;i<4;++i){
                        if (month==monthOfThirty[i]){
                            // 1-30
                            if (day<=30){
                                return valid;
                            }else{
                                return dayInvalid;
                            }
                        }
                    }
                }
                // month非法
                else{
                    return monthInvalid;
                }
            }
    
            // year非法
            return yearInvalid;
        }
    
        // 计算下一天
        private String calcNextDate(){
            int yearNext;
            int monthNext;
            int dayNext=day+1;
            int dayCarry=0;
            int monthCarry=0;
    
            // 处理day
            // 是2月
            if (month==2){
                // 闰年
                if (yearIsLeap(year)){
                    // 1-29
                    if (day==29){
                        dayNext = 1;
                        dayCarry = 1;
                    }
                }
                // 平年2月
                else{
                    // 1-28
                    if (day==28){
                        dayNext = 1;
                        dayCarry = 1;
                    }
                }
            }
            // 不是2月
            else{
                boolean isThirtyOne= false;
                // 是否为31天的月
                for(int i=0;i<7;++i){
                    if (month==monthOfThirtyOne[i]){
                        isThirtyOne = true;
                        // 1-31
                        if (day==31){
                            dayNext = 1;
                            dayCarry = 1;
                        }
                        break;
                    }
                }
    
                // 至此能保证是30天的月
                if (!isThirtyOne){
                    // 1-30
                    if (day==30){
                        dayNext = 1;
                        dayCarry = 1;
                    }
                }
            }
    
            // 处理月
            if (month+dayCarry>12){
                monthNext = 1;
                monthCarry = 1;
            }else{
                monthNext = month+dayCarry;
            }
    
            //  处理年
            yearNext = year+monthCarry;
    
            return yearNext +"/"+ monthNext +"/"+ dayNext;
        }
    
        // 判断某一年是否为闰年
        private boolean yearIsLeap(int year){
            // 普通闰年和世纪闰年
            if ((year%4==0&&year%100!=0)||(year%400==0)){
                return true;
            }
    
            // 平年
            return false;
        }
    }
    
    

    DateUtilTest.java

    package com.test;
    
    import com.company.DateUtil;
    
    import static org.junit.Assert.*;
    import org.junit.Test;
    
    //1、参数化测试:引入相关的包和类
    import java.util.Collection;
    import java.util.Arrays;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Parameterized.Parameters;
    
    @RunWith(Parameterized.class) //2、参数化测试:更改测试运行器为RunWith(Parameterized.class)
    public class DateUtilTest {
        //3、参数化测试:声明变量用来存放预期值与结果值
        private DateUtil util = new DateUtil();
        private String date;
        private String except;
    
        //4、参数化测试:声明一个返回值为 Collection 的公共静态方法,并使用@Parameters 进行修饰
        @Parameters
        public static Collection data(){
            return Arrays.asList(new Object[][]{
                    {"2004/12/25", "2004/12/26"},
                    {"2001/2/28", "2001/3/1"},
                    {"2000/2/29", "2000/3/1"},
                    {"2001/4/30", "2001/5/1"},
                    {"2001/5/31", "2001/6/1"},
                    {"1899/6/1", "year非法"},
                    {"2051/6/1", "year非法"},
                    {"a/6/1", "year非法"},
                    {"1999/0/1", "month非法"},
                    {"1999/13/1", "month非法"},
                    {"1999/a/1", "month非法"},
                    {"1999/1/0", "day非法"},
                    {"1999/1/32", "day非法"},
                    {"1999/1/a", "day非法"},
                    {"2001/2/29", "day非法"},
                    {"2000/2/30", "day非法"},
                    {"2001/4/31", "day非法"},
            });
        }
    
        //5、参数化测试:为测试类声明一个带有参数的公共构造方法,并在其中为声明变量赋值
        public DateUtilTest(String date, String except){
            this.date = date;
            this.except = except;
        }
    
        @Test
        public void testGetNextDate(){
            assertEquals(except, util.getNextDate(date));
        }
    }
    
    

    测试结果

    如下图所示,17个测试用例均测试成功,程序实际输出与期望值相同。

    测试结果.jpg

    实验总结

    本次实验的主要目的是巩固黑盒测试方法中的等价类划分法的知识,练习JUnit的参数化测试。在本次实验中,我认为我的getNextDate函数的实现并不是很优雅,比较过程化。写这个函数花了我很多时间,主要问题在于我没有抓住一些关键的、抽象的逻辑和子函数,比如天向月份进位和月份向年份完全可以参照加法器的循环、可以写一个函数根据年份和月份判断出天数的最大值等等。


    作者:@臭咸鱼

    转载请注明出处:https://www.cnblogs.com/chouxianyu/

    欢迎讨论和交流!


  • 相关阅读:
    第五篇:JMeter 定时器
    第四篇:JMeter 性能测试基本过程及示例
    第三篇:JMeter 组件手册
    第一篇 HTTP 协议报文结构及示例
    第二篇 JMeter 目录及关键配置分析
    第一篇:什么是 JMeter和为什么选择Jmeter做性能测试
    教你如何识别百度蜘蛛IP含义
    DEDECMS安装之后需要做的安全处理和须知
    织梦联动类别-地区调用不显示第三级城市的原因
    CSS的特效
  • 原文地址:https://www.cnblogs.com/chouxianyu/p/12791558.html
Copyright © 2020-2023  润新知