软件工程课程第二次作业(结对项目)

软件工程课程第二次作业

曾沅伟 M23120103  马超 M23185402

一、任务分工

曾沅伟:

①博客撰写;

编写代码程序以实现“对历史成绩进行存储和查询”这一需求,包括用户名和成绩存储、成绩查询、历史成绩显示的功能;

③性能分析。

马超:

编写代码程序以实现其他7个需求;

②单元测试;

③建立里程碑。

二、代码仓库中项目地址

MaChao_Zeng yuan wei: 作业实践 (gitee.com)

或者https://gitee.com/hezhiyong_edu/autumn-2023

三、PSP表格以及分析

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

60

60

· Estimate

· 估计这个任务需要多少时间

60

60

Development

开发

1180

1300

· Analysis

· 需求分析 (包括学习新技术)

240

260

· Design Spec

· 生成设计文档

120

130

· Design Review

· 设计复审

60

90

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

40

60

· Design

· 具体设计

120

140

· Coding

· 具体编码

410

420

· Code Review

· 代码复审

70

80

· Test

· 测试(自我测试,修改代码,提交修改)

120

120

Reporting

报告

260

300

· Test Repor

·测试报告

100

120

· Size Measurement

·计算工作量

60

70

· Postmortem & Process Improvement Plan

·事后总结, 并提出过程改进计划

100

110

合计

1500

1660

从上面的PSP表格中可以得知,个人开发软件项目的部分过程的预估耗时和实际耗时存在一些偏差,总体来看是实际效率比预期效率稍低。究其原因是我们小组两人对整个软件开发的流程以及每个过程应该做什么工作还不是特别的清楚,同时我们本身不是计算机专业学生,对于编程这一块还有部分短板,在设计代码规范、编写代码以及代码复审这块实际用时较多。

四、每日软件工程学习日志

曾沅伟的学习日志:

学习时段

学习内容

收获体会

自我效率评价

10171420-1630

阅读邹欣老师的博客:现代软件工程讲义 2 工程师的能力评估和发展

个人比较喜欢体育,文章用足球团队流程以及篮球运动员的赛场数据深深吸引了我去阅读,也对PSP各个阶段有了新的认识

对自己喜欢的事情比较上心,总体效率较高

10171840-1930

制作PSP表格并填写各个阶段完成时间的估计值

表格制作还是比较简单的,但对于阶段完成时间的估计可能有许多不确定因素

总体效率较高

10172000-2130

阅读邹欣老师的博客:源代码管理

这篇文章以老师和学生的对话为切入点,能将软件工程的质量和生活中建房子的质量很好的结合起来,我明白了源代码管理工具和构建系统对于软件质量的重要性,也通过10个实践问题对代码的编写、修改以及测试有了新的认识

总体效率较高

10月19日0900-1000

编写并在仓库中提交四则运算程序代码:历史成绩存储

使用了很久没有使用过的文件指针编写程序,重新唤起了记忆,感觉非常有成就感

一日之计在于晨,个人感觉能充分利用好时间,效率较高

10191440-1650

编写并在仓库中提交四则运算程序代码:显示历史成绩

代码编写思路与上一步相似,进一步充实了整个程序框架

总体效率一般

10191900-2100

阅读阮一峰的博客:Commit message 和 Change log 编写指南

Commit message的作用、格式以及生成Change log有了初步的了解

总体效率较高

10200810-1000

编写并在仓库中提交四则运算程序代码:用户名和历史成绩查询

我在本科期间开发的“在线考试系统”中也有“用户名和历史成绩查询这一功能”,感觉找到了曾经的灵感,同时对文件指针的运用更加熟练

一日之计在于晨,个人感觉能充分利用好时间,效率较高

10201100-1140

阅读邹欣老师的博客:现代软件工程讲义 2 开发技术 - 单元测试 & 回归测试

重点对单元测试的编写以及好的单元测试标准进行了阅读,发现与教授在课上讲的基本一致,能很好的理解其内涵和要点,同时也了解了回归测试

一上午都在编写程序代码以及撰写博客,到这时注意力容易分散,效率有所下滑

10211420-1500

完善PSP表格:填写各个阶段完成时间的实际值

通过估计值与真实值的比较,既能明显反映出开发软件项目效率的高低,也能衡量软件开发的质量和工作量

总体效率较高

马超的学习日志:

学习时段

学习内容

收获体会

自我效率评价

16

程序编写和C语言基础知识学习

初步构建了四则运算基础框架,落实双人具体分工,编写main函数,确定程序中主要功能模块、自定义函数及重要变量。

学习C语言知识:C语言标准函数库,为后续程序中调用各种函数打好基础。

一般

17

程序编写和C语言基础知识学习

学习C语言知识:随机数生成和switch函数使用。在程序中定义能生成随机整数和随机运算符的函数。

一般

18

程序编写和C语言基础知识学习

学习C语言基础知识:如何定义宏。

完成文件头、主函数、随机数和运算符生成函数等代码上传同步。

一般

19

程序编写和C语言基础知识学习

学习C语言基础知识:文件系统操作,学会如使用库函数数据写入本地或从本地读数据并赋给变量。对实施计算功能的函数定义具体算式生成细节。

一般

五、解题思路描述

(一)思考过程

1、分析本题程序要实现的需求,确定函数总体框架

首先要明确程序要实现的需求,即

①题目数量可以指定;

②支持加减乘除4种运算;

③每道题包含两个运算符;

④运算数为100以内的数字;

⑤保证答案在0..100之间;

⑥需要有答题功能并验证答案是否正确;

⑦可以判分并对历史成绩进行存储和查询;

⑧题目避免重复。

针对这8个需求,想要全部实现,初步判断至少需要8个函数,同时可能会增加实现“显示题目”这一隐含需求的函数。此外,“保证答案在0~100之间”和“需要有答题功能并验证答案是否正确”这两个需求有共同之处,可以用一个函数实现。最后,需要设计一个主函数(main)来调用这些函数。

2、做好编程以及博客撰写分工

后续通过和我的搭档密切协商,决定由我主要负责博客的撰写和程序性能分析,同时也编写代码程序以实现“对历史成绩进行存储和查询”这一需求,虽然只有一个需求,但这一需求可能需要的功能函数也较多,包括用户名和成绩存储、成绩查询、历史成绩显示等功能。

我的搭档负责实现其他需求的代码编写以及总程序的单元测试。

3、搜集相关资料

这一过程描述将在(二)找资料过程中具体体现。

4、分块编写程序代码

根据分工,需要我和搭档按照时间计划编写相关函数的代码,满足题中明确的编码要求,定期在仓库中提交、评审以及合并,最终完成整个程序代码的编写。

5、在仓库中提交、评审以及合并

需要我定期在仓库中提交代码,请搭档评审以及合并,最终完成整个程序代码的编写。

6、单元测试

正如教授在上课时所说,程序能正常运行,不代表它没有错,不存在bug。因此需要在完成整个程序代码编写的基础上,实现对程序的单元测试,以保证程序的正确性,这就需要借助Visual Studio 2022的编程环境通过编写单元测试代码来实现。

7、撰写博客

需要满足题中的博客撰写要求。

(二)找资料过程

1、阅读《现代软件工程讲义2 工程师的能力评估和发展》

寻找并学习与PSP表格的有关内容,了解个人软件开发流程的各个阶段,从他人对实现个人软件开发过程的时间记录和效率分析中获取灵感和启发,以便于自身更好完成“记录工程师如何实现需求的效率”这一任务。

2、阅读邹欣老师的博客:源代码管理

搜集并学习与源代码管理有关的知识点,了解源代码管理的10个实践问题,

进而掌握代码的编写、修改以及测试的具体流程和细节,为在Gitee上实现代码签入打下坚实理论基础。

3、阅读《阮一峰的博客:Commit message 和 Change log 编写指南》以进一步了解Commit

4、阅读《邹欣老师的博客:现代软件工程讲义 2 开发技术 - 单元测试 & 回归测试

期望获取有关利用编程环境编写单元测试代码以及如何设计测试用例的有关知识。

六、设计实现过程

(一)代码组织

根据需求进行代码功能划分,要实现的目标程序要包含以下功能:

1)产生100以内的随机数;

2)从加减乘除四种运算符中随机选出一个运算符;

3)保证在一题中先进行乘除运算,后进行加减运算;

4)用符号定义加减乘除四种运算符;

5)显示题目;

(6)存储用户名和成绩;

7)显示历史成绩;

8)建立练习模块;

9)查询历史成绩。

(二)函数关系

要实现(一)中的所有功能,需要两类函数:调用函数和被调用函数,包括1个主函数(调用函数)和9个被调用函数,分别为:

int main();

int generateRandomNumber();

char generateRandomOperator();

double calculate(int num1, char op1, int num2, char op2, int num3);

double _calculate(double num1, char op, double num2);

void displayQuestion(int num1, char op1, int num2, char op2, int num3);

void storeScore(int score, char *username);

void displayScores();

void practice();

void find();

②-⑩的9个函数分别对应9个要实现的功能,呈一一对应的关系,但⑨void practice()中需要调用②int generateRandomNumber()、③char generateRandomOperator()、④double calculate(int num1, char op1, int num2, char op2, int num3)、⑥void displayQuestion(int num1, char op1, int num2, char op2, int num3)、⑦void storeScore(int score, char *username)5个函数,因此⑨void practice()可作为关键函数。

(三)关键函数流程图

如下是关键函数void practice()的流程图:

(四)单元测试设计

本次单元测试使用LDRA Testbed测试工具中的Tbrun进行,其具有操作简单、上手快、窗口化操作、无需编写脚本等优势,测试环境为虚拟机中的windows XP(32位)环境。

1、测试对象的选择

打开虚拟机中的单元测试工具LDRA Testbed,点击Testbed的菜单Fileàselect file 通过文件浏览窗口打开文件要分析的文件teamproject.c。

点击select之后,可以在工具快捷按钮栏的下方看见目前选择的文件。

2、单元测试模块Tbrun的打开

Testbed进入Tbrun有三种模式,每种模式对应不同的测试类型,三种模式分别为:“Integration Unit / Module Test”、“Isolation Unit / Module Test”和“Unit Test Only”。由于我们使用的代码为C语言,故使用“Unit Test Only”模式,CPP的单元测试使用另外两种模式皆可。

Testbed菜单TBrunàUnit Test Only点击,即可进入Tbrun模块。

3、测试序列(Sequence)的创建

Tbrun中是使用测试序列(sequence)来容纳测试用例和测试数据的,进入Tbrun后第一步需要做的就是创建测试序列。

Tbrun的菜单Sequence-àNew点击,弹出测试序列创建窗口,在“Sequence name”下面需要用户写入Sequence的名字;窗体下面的选项卡设置如下:

4、测试用例的创建

Tbrun窗体的右上角File View窗口中,点击文件名能够展开显示文件中所包含的函数,把鼠标放到某个函数名上,右键弹出菜单点击“Create New Test Case”。

在此窗口中会显示函数的基本信息,可不用关注,直接点击按钮“Continue”向下进行,这样一个用例创建完成,可在用例管理窗口“Test Case View”中显示已经创建的用例,以数字编号用例,在“Variable I/O View”窗口中会显示此函数的输入输出参数。

在此窗口中会显示函数的基本信息,可不用关注,直接点击按钮“Continue”向下进行,这样一个用例创建完成,可在用例管理窗口“Test Case View”中显示已经创建的用例,以数字编号用例

在“Variable I/O View”窗口中会显示此函数的输入输出参数。

5、测试用例的输入输出参数IO值设定

测试用例的输入输出参数值的设定是测试的核心,在这一步决定了有什么样的输入和用例运行之后应该有什么样的输出(预期输出),从而实现了函数功能的验证。对于函数的输入输出不只有函数的参数,还包含函数内部使用的全局变量。

在“Variable I/O View”窗口中工具会显示出函数的参数和内部使用的全局变量,并会显示每个参数是输入还是输出,用户给每个参数赋值即可,注意输入以“I”标示的,输出是以“O”标示的,此处的输出是指预期的输出值。

对于标示为“I”的变量一定要有一个确定的值,要不让用例无法执行。

6、测试用例的执行

测试用例的IO设置设定之后,此用例就算构造完成了,接下来要做的就是执行用例,有两种运行方式,操作方法如下:

一键式运行用例;在测试用例管理窗口中的空白处右键可弹出菜单,点击“Run Test Case Driver”即可运行用例。

分步式执行用例;在测试用例管理窗口中的空白处右键可弹出菜单,按顺序点击“Generate Driver”、”Build Driver”、”Execute Driver”、(“Split Regression Driver Output”)、”Process Regression Driver Output”,每执行一步如果执行成功则会在旁边以“”提示,如果不成功则没有“√”,请排查原因。

7、测试结果的查看

    下面以十个用例测试的第一个,generateRandomNumber函数功能测试为例

单元测试其测试结果由两部分构成:函数功能验证和函数覆盖率信息。

函数功能的验证是通过用例的执行之后的用例确认对话框中的Pass/Fail结果反映的,我们可以点击界面中的Report,生成测试报告。

可以看到测试结果显示PASS通过。

以下为剩余9个用例的测试列表

七、性能分析及程序改进

(一)性能分析

使用Visual Studio 2022中内置的性能探测器对四则运算的总程序进行性能分析,分析内容包括:CPU使用率和内存使用率。

1、程序调试运行

2、生成性能探测报告

1内存使用率情况

从图中可以看出,进程内存基本上都是专用字节,总计796KB,是一个可以接受的范围。

(2)CPU使用率情况

 从上图中可以看出,程序中CPU消耗最大的函数为main函数,其具体代码如下:

(二)程序改进

从以上性能分析情况得知,这个四则运算的总程序总体性能良好,但还可以从以下2个方面进行进一步改进:

1、使用 const 关键字声明常量,以提高代码的可读性。

如下是在practice()函数中的第185行利用const重新对常量isRepeated进行声明。

2添加注释,以帮助其他开发人员理解代码的功能和实现方法。

在第249行添加注释“文件为空无法打开”,在第265行添加注释“提醒用户查询成功与否”。

八、代码说明

如下是关键函数⑨void practice()的关键代码:

void practice() // 定义练习模块函数

{

    int numQuestions, score = 0; // 声明变量出题数,定义分数并初始化为0

    char username[50];

    printf("请输入用户名:");

    scanf("%s", username); // 输入用户名

    printf("请输入题目数量(结果保留小数点后两位): ");

    scanf("%d", &numQuestions); // 输入出题数

    int previousQuestions[100][5]; // 声明整型二维数组,保存历史题目,最多100题

    for (int i = 0; i < numQuestions; i++)

    {

        int num1, num2, num3; // 声明3个随机数

        double answer;        // 声明一个结果数

        char op1, op2;        // 声明两个随机运算符

        // 生成题目并验证是否重复

        int isRepeated = 0;

        while (1)

        {

            num1 = generateRandomNumber(); // 声明3个随机数,两个随机运算符

            num2 = generateRandomNumber();

            num3 = generateRandomNumber();

            op1 = generateRandomOperator();

            op2 = generateRandomOperator();

            int idx = 0;

            for (int j = 0; j < i; j++)

            {

                if (op1 == '/' && num2 == 0)

                {

                    idx = 1;

                    break;

                }

                if (op2 == '/' && num3 == 0)

                {

                    idx = 1;

                    break;

                }

                if (num1 == previousQuestions[j][0] && op1 == previousQuestions[j][1] && num2 == previousQuestions[j][2] && op2 == previousQuestions[j][3] && num3 == previousQuestions[j][4])

                {

                    idx = 1;

                    break;

                }

            }

            if (calculate(num1, op1, num2, op2, num3) >= 0 && calculate(num1, op1, num2, op2, num3) <= 100 && idx == 0)

                break;

        }

        displayQuestion(num1, op1, num2, op2, num3); // 显示问题

        printf("请输入答案: ");

        scanf("%lf", &answer); // 输入答案

        //;

        double calculatedAnswer = calculate(num1, op1, num2, op2, num3); // 检查输入答案正确答案是否正确相符,并在0到100之间

        if (fabs(round(answer * 100) - round(calculatedAnswer * 100)) < 1)

        {

            printf("回答正确!\n");

            score++;

        }

        else

        {

            printf("回答错误。正确答案是: %lf\n", calculatedAnswer);

        }

        previousQuestions[i][0] = num1;

        previousQuestions[i][1] = op1;

        previousQuestions[i][2] = num2;

        previousQuestions[i][3] = op2;

        previousQuestions[i][4] = num3;

    }

    // 存储成绩

    storeScore(score, username);

}

编写函数代码的思路:

主要是建立在对需求以及对应功能进行综合分析的基础上,结合前期已经声明过的相关函数,将一些目标功能进行整合,力争通过一个函数来实现这些功能的思路。

首先站在用户的角度上进行全流程思考:要想进行四则运算练习,必须先输入自己的用户名以及需要做题的数量,然后能根据系统随机产生随机数以及随机运算符号所形成的题目并进行相应作答,作答之后能显示相应答案以及判断是否与正确答案相符,最后知道自己的分数并自动存储至历史记录。

再站在我们结对两人的角度进行思考:可以在前期已经建立起的②int generateRandomNumber()、③char generateRandomOperator()、④double calculate(int num1, char op1, int num2, char op2, int num3)、⑥void displayQuestion(int num1, char op1, int num2, char op2, int num3)、⑦void storeScore(int score, char *username)5个函数的基础上,增加代码把这些函数连接起来,将这个函数作为关键函数,也就是实现总体功能的主模块。

九、心路历程与收获

拿到这个项目问题之后,我们小组两人开始很疑惑,虽然都知道得先编程,并且写代码是关键,但对整个软件开发的流程以及每个过程应该做什么工作还不是特别的清楚。于是我决定先从PSP表格制作开始入手,从PSP表格去了解个人软件开发流程,所以我就去阅读了题中推荐的有关PSP的博客文章。有一篇文章用足球团队流程以及篮球运动员的赛场数据深深吸引了我,我也对PSP各个阶段有了全新的认识,以及构建起整个开发过程的框架。

之后结合构建之法的有序学习过程,我着手开始编写实现相关功能的函数代码,并对代码进行了性能分析。但这一过程耗费了大量的时间,因为对于编程这块我还达不到非常熟练的地步,我也是通过经常和搭档协商讨论,互相上传至代码仓库进行评审修改,最终才把程序完完整整地写出来。

在写代码的过程中我也有计划地开展博客的撰写,从最后结果来看,我们小组两人对此比较满意,所有的努力都没有白费,收获颇多。我至少对软件开发的整个流程及每个过程应该做什么工作有了清楚的认识,也通过构建之法相关博客的学习,对代码的设计规范、评审以及单元测试有了更深层次的理解,同时我的计算机编程能力也有所提高,希望能更好地完成后续作业任务。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值