林喜文?李佳佳?高凤毅?张淑桐
摘要:针对软件工程课程教学中出现的重理论、轻实践的现状,从课赛融合的角度,以单元测试知识点为例,将全国职业院校技能大赛软件测试赛项考察的核心技能引入教学中。但是,软件工程课程的目的不在于深入学习编程技术,而是侧重于如何将工程的思想引入软件的开发和维护中。因此,教学案例要尽量降低对编程语言和编程技术的依赖。根据以上特点,案例设计采用Python编程语言,借助海龟编辑器和PyCharm集成开发环境,力求增加学生的学习动力并达到教学目的。
关键词:软件工程;单元测试;课赛融合;Python
一、前言
软件工程课程的教学实践一直致力于培养学生的软件开发技能和工程思维能力。在现代软件开发中,高质量的代码和可靠的软件系统是至关重要的,而单元测试作为软件测试的基础,起着至关重要的作用。通过单元测试,开发人员可以确保代码的正确性、可靠性和健壮性,从而提高软件的质量并减少后期维护成本。为了改进软件工程课程的教学实践,采用了基于课赛融合的教学方法,将单元测试作为一个重要的教学内容进行深入学习和实践。通过将理论知识与实际项目结合起来,学生可以亲身参与到软件开发过程中,并在实践中学习单元测试的重要性和实际应用。
二、软件工程教学现状
软件工程是计算机类专业高年级的一门必修课程。该课程综合性很高,立足于软件开发全生命周期(见图1),将学过的各个课程有机融合在一起,因此在教学中容易给学生留下“知识面广、知识点浅”的印象。这种重点不明确、过度强调理论知识的教学模式会极大损害学生的学习积极性[1]。针对以上现状,有关软件工程的课程改革研究层出不穷,但无一例外都倡导理论与实践结合、案例式教学的思想。不同于任何一门编程类课程,软件工程课程的侧重点在于如何将工程的思想引入软件的开发和维护中。知识、技术、工具是手段,最终目的是在有限的资源下按计划完成特定目标。因此,在开展软件工程课程的实践教学时,过度深入某个特定的技术点并不利于达到课程目标。在选择软件工程教学案例时,既需要满足本课程侧重点,也需要遵循特定的学习方法[2]。
三、基于课赛融合的单元测试案例设计
在软件生命周期中,软件测试是保证软件质量的重要手段,其中,单元测试负责对最小的功能模块进行验证[3]。研究表明,单元测试能发现约80%的软件缺陷,因此,单元测试在软件开发过程中的重要性不言而喻。本文中,单元测试教学案例参考2022年全国职业院校技能大赛“软件测试”赛项(以下简称“国赛”)任务二题目1,但是进行了以下适应性调整:一方面,“国赛”中要求使用Java语言的JUnit框架,为适应软件工程课程的特点,不刻意追求编程技术难度,在实际教学要求中调整为使用Python语言的Unittest框架;另一方面,“国赛”中项目二题目1只要求满足语句覆盖,但是在单元测试的教学范围中还包括判定覆盖、条件覆盖、判定条件覆盖、条件组合覆盖以及路径覆盖,因此在教学要求中追加后几种覆盖方式[4]。
四、实验过程
(一)编写程序
为完成本案例,首先使用PyCharm创建项目unitTest,此时项目下会自动创建__init__.py文件。此外,func.py文件中用来保存实现图2中所示流程图功能的函数getRes(x, y);__init__.py文件中用来编写针对func.py单元的测试代码;getResult.py文件用来实现完整的输入、输出的功能。还需要在该项目下创建文件func.py和getResult.py,项目整体文件结构见图3。
由于软件工程课程的目的不在于深入学习编程技术,为消除学生对Python编程语言的依赖,因此在定义func.py文件中的函数getRes(x, y)时,引入海龟编辑器来完成[5]。海龟编辑器是面向国内Python学习者的一款编程学习工具。其界面友好,可以让用户以搭积木的方式来学习Python,能有效提高学习兴趣,降低编程的枯燥感。此外,由于其积木模式和代码模式可以任意转换,也保证了Python代码编程的专业度。
海龟编辑器界面用不同的颜色区分积木类型,为实现getRes(x, y)的函数定义,依次用到了函数、控制、运算、变量中的不同积木。其主框架是使用了一块大的“如果—否则”积木,并在其中嵌入两块小的“如果—否则”积木。要注意的是,需要在变量中创建变量a,用来保存函数返回值[6]。通过积木的拖动以及匹配不同积木之间凹凸接头,可以很容易得到getRes(x, y)的积木模式,如图4所示。将积木模式切换为代码模式,就可以得到getRes(x, y)的Python代码,这部分代码可以直接复制到func.py文件中。
__init__.py文件使用Unittest单元测试框架对func.py文件中定义的getRes(x, y)函数进行测试,代码分为三个部分,具体如下:
1.导入Unittest框架与func.py文件中的MyClass类。
import unittest
import func
2.定义mytest单元测试类,其中包括setUp、tearDown以及针对每个测试用例的测试类,以此对func单元进行测试。
class mytest(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
#测试用例1_1,x和y的输入为85和65,a的预期值为2
def test1_1(self):
self.assertEqual(func.getRes(85,65),2,'test1_1 success')
'''其他测试用例的输入及预期值均可参考test1_1在下方定义测试类'''
3.建立main()函数,构造测试集并执行测试。
if __name__=='__main__':
unittest.main()
getResult.py文件中也需要首先导入func.py文件中的MyClass类,再使用input和print函数实现x值和y值的输入以及a值的输出。
import func
x = int(input('请输入x:'))
y = int(input('请输入y:'))
print('a=', func.getRes(x, y))
(二)选择测试用例
单元测试包括语句覆盖、判定覆盖、条件覆盖、判定条件覆盖、条件组合覆盖以及路径覆盖等六种类型。其含义分别为:
1.语句覆盖:使程序中每个语句至少执行一次;
2.判定覆盖:使每个判定的真假分支都至少执行一次;
3.条件覆盖:使每个判定的每个条件的可能取值至少执行一次;
4.判定条件覆盖:能同时满足判定、条件两种覆盖标准的取值;
5.条件组合覆盖:使程序中所有判定的条件组合至少执行一次;
6.路径覆盖:使程序中每条路径至少执行一次。
在充分解释以上覆盖原理后,学生将为本案例选择测试用例,测试用例的选择及其结果将按照表1的格式进行填写。
(三)执行程序
首先,执行getResult.py文件,确保程序可以从键盘得到x值和y值的输入,并得到输出的a值,控制台的输入、输出界面见图5。
接下来执行__init__.py文件对func单元进行测试。例如,为满足语句覆盖选择了3个测试用例,在PyCharm执行后得到图6所示界面,测试结果均为绿色对号,说明3个测试用例均通过。为满足条件覆盖选择了3个测试用例,执行后得到图7所示界面,测试结果中出现黄色的叉号,说明有测试用例没有通过。这时候需要检查被测单元的代码或者测试用例的选择以及预期结果是否正确[7]。
五、结语
为提高软件工程课程授课效果,本文以单元测试知识点为例设计了一个教学案例。其中融入了全国职业院校技能大赛软件测试赛题,以达到在教学中将理论与实践相结合的目的。由于软件工程侧重点在于将工程的思想引入软件的开发和维护中,并不是一味追求编程技术的难度,而是为了在有限的资源下,借助知识、技术、工具,按计划完成特定目标。本案例的设计可以让学生在学习过程中掌握单元测试知识,熟悉Python编程技术,了解海龟编辑器和PyCharm工具。
参考文献
[1]杨波,许福,李冬梅,等.针对软件工程课程的人工智能实验案例设计[J].计算机教育.2022,333(9):202-206.
[2]洪玫,严斌宇,余静.面向学生能力培养的课程教学设计——以软件工程专业为例[J].中国大学教学.2022,383(7):39-44.
[3]郭永平,马巧梅,龙飞,等.沉浸式软件工程专业实训课程设计与实践[J].计算机教育.2022,331(7):175-179.
[4]管青.沙盘模拟式项目驱动的软件工程教学模式[J].计算机教育.2021,322(10):143-146.
[5]蒋虹,祁小明.Python起步教学的有效策略探讨[J].中国现代教育装备.2023,402(0):43-45+49.
[6]张苏,杨元峰,陆公正.软件测试中单元测试案例教学实践[J].电脑知识与技术.2020,16(13):132-135.
[7]赵春霞,曹莉,赵营颖.基于“项目导向+任务驱动”的课程教学模式研究——以软件工程课程为例[J].科技视界.2021,365(35):46-47.