片面追求单元测试覆盖率之我见

格兰特杨 2010-06-12 06:44:14
一些个人之见,讲出来希望大家讨论。这完全是工作中遇到的一些具体问题抽象出来的一个东西,仅属于个人之见,任何的意见都是欢迎的。

----------------------------------------------------------------------
在工作中,当被问到“如何提高代码质量”,回答无非如下几个,增加评审,代码规约,单元测试。不知起自何年何月,如今一些机构开始引入“单元测试覆盖率”的概念,并由此对程序员提出了覆盖率要达到70%,90%,以此来评判程序员工作的质量,以及产品的质量。这里先预为单元测试下定义以免混淆,即,基于Junit,类与代码级别的,与运行时无关的白盒测试。

而单元测试覆盖率,何以得知呢?一个(当然不是所有)最常使用的办法便是如cobertura之类的工具来执行Junit的测试用例,这些工具不会去统计程序的逻辑,而是判断用例执行到的行数。如果再引入hudson一类的持续集成工具,便可生成漂亮的日报表,管理层也就可能直接地了解这些技术数据。这些都是好的实践,但我想说的并非这些,而是想与大家探讨这些数据是否与产品的质量有着必然的相关。

写过测试用例的朋友们一般地会了解,测试用例与接口有必然的关联,而多数情况下会是直接调用。修改接口会带来测试用例的修改,这是多数情况下不争的事实。有人说为测试可以预留专用的接口,但这种做法在一个要求代码安全的机构中不会得到接受。所以,代码评审/重构或代码上下文变更导致的接口变化,多数情况下会带来测试用例的修改;用例越丰富,这部分的工作量越大,此其一。

其二,讨论单元测试覆盖率与正确代码逻辑的相关性。我们需要衡量的代码的逻辑,乃是在运行时外部触发系统时可能运行的所有逻辑,其包含接口内部逻辑,也包含接口调用逻辑。当接口间存在内容耦合和控制耦合时,合理的测试用例中对于接口间的调用顺序和想定上下文都有要求,与覆盖率并不相关。如a-b-c与c-b-a的调用,覆盖率完全相同,但结果可能完全不同。这一点在测试状态机相关的代码时显得更为重要。

其三,我们经常说到20%和80%的关系。即有80%的时间应当用在20%重要性的事情上。反观程序员写的代码,关键模块与非关键模块的比例也如是。倘时间不是问题自然可以把所有的事情做到完美,一旦时间是问题,哪一个优先,自一目了然。问题是,关键模块由于逻辑复杂,依赖较多,往往是最难测试,其用例也最难写作。人性往往倾向于先易后难。若覆盖率是唯一的指标,最关键的部分便很容易因为覆盖率目标已经达到而被忽略,80%的覆盖恰恰没有覆盖的是最应该测试的代码,很不幸,最易测试的,是那些对于POJO,数据库,配置文件操作的清晰逻辑,通过一个集成测试的用例就可以全部保证的。

那末,为什么覆盖率会成为这样多项目经理趋之若鹜的管理方法呢?显然,这是一个节约管理成本可见收效的举措。只需要把cobertura和hudson配好了放在那里并说明给所有程序员,就可以坐看数字一天一天的上升而觉得质量在一天一天地变好,不需要组织什么评审,不需要去过问每一个人的状况,不需要再去费力地去看报告,何乐而不为?

容我说,懂得我上面说的话,却坚持还要这样做的人可以被看成软件项目管理中的官僚主义。人力就是人力,它不会凭空变少,也不会凭空变多。用在70%-90%覆盖率上的人力成本,与其他方法比起来值与不值?软件工程没有银弹,只有综合各种方法形成最适合自己产品的方法才是最好的质量控制。在我个人看来,就单元测试而言,确定我们拥有高质量的测试用例,确定关键的模块都有相关的测试对应,比简单地追求覆盖率要重要得多。而这些通过传统的评审和走查可以轻易做到的事情,却常常被我们定义流程和日常管理中忽略了。
...全文
939 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
andycode 2011-03-20
  • 打赏
  • 举报
回复
麻烦介绍几本单元测试书籍。
格兰特杨 2010-06-22
  • 打赏
  • 举报
回复
@jason_dct:

我个人认为开发人员的测试在测试驱动的流程中更加有意义。传统的瀑布流程并非一无是处,对于需求稳定的系统它能够做出更加坚实的架构和更加明确的里程碑。在瀑布流程中,开发人员也许会更多关注自动化的集成测试;而敏捷/XP中,测试在很早就被引入,而此时并不具备完整集成测试的条件,也许这也是我们也经常叫这类测试为“单元测试”的原因之一。其实,个人的理解这些流程并无规定测试的具体方法。若是测试框架比较完整,在敏捷中使用持续集成测试也完全可能。
格兰特杨 2010-06-22
  • 打赏
  • 举报
回复
@sp1234:

看得出您在XP方面有相当多的经验。如果您有时间的话,我想和您探讨一下,在您基于XP开发的项目中,如何保证测试用例的质量的,以及怎样平衡解决重构带来的成本与时间表的冲突?谢谢。

格兰特杨 2010-06-22
  • 打赏
  • 举报
回复
@ericzhangali: 呵呵。我只是表达观点,并不想吵架。所以有些贴子我回,有些我不是很想回复。我想你看了有些回贴也能够理解。

@sp1234: 相信我们的大部分观点是一致的,握手!对于您的"我的书架上就有至少2本十几年前的、我认为现在也很难找到相当水平的关于传统自动化测试书籍,可是它们毕竟都是过时的、有害的书籍,虽然写得太好、那些理论太能用来忽悠人了。"这句话,我深表赞同。

@microtry:
这里,再次深感把概念统一是进行深入讨论的基础。对于“单元测试”这四个字如果大家还没有统一的认知,则很多讨论就是自我自话,鸡同鸭讲。其实我一再强调我说的是基于xUnit的狭义的单元测试,可能很多人还没有了解。再说一遍,我反对的就是覆盖率即质量本身这样的论断,而且请万万不要把“追求质量"和“追求覆盖率”相提并论,这是有害的,而且会误导大量的程序员和项目经理。

1. 用工具统计出来的“覆盖率”,是执行xUnit测试时走过的代码率,是不是与书本上讲的“覆盖率”是一回事,值得讨论,至少不能代表逻辑覆盖率。
2. 有限的人力资源,是否需要优先用在更有针对性的测试上,而不是盲目要求一个覆盖率的百分比。覆盖率百分比高,并不能代表最重要的部分已经被覆盖。至于说到100%覆盖率,有一句话要奉送,纸上谈兵不如退而结网。
3. 有很多其他有效的方式可以控制质量,单元测试只是其中之一,而且不是万能的。如@sp1234所讨论的,在XP的流程中,单元测试用来驱动开发,关键的持续质量提升在于持续的重构。
4. 我无意就一些浮在空中的理论做一些漫无边际的探讨;在某本书上抄一些理论贴在这里,并做一些想当然却似是而非的论断是很容易的,把这些论断用在生产中则是另外一回事。所以您的第2,3,4条,请允许我不做评论。
loveisbug 2010-06-20
  • 打赏
  • 举报
回复
看楼主怎么掰回去。
小_虎 2010-06-19
  • 打赏
  • 举报
回复
买了本《.Net自动化测试之道》,一直没看,刚买回来,就忙死了。
  • 打赏
  • 举报
回复
TDD需要非常好的编写代码能力,和比较清晰的头脑,是对编程技术的高要求。国内的手工测试人员,基本上不胜任。
段传涛 2010-06-19
  • 打赏
  • 举报
回复
我也在学习研究,看了一下博客园的文章,现在好像项目经理比较喜欢这个,我个人认为程序员测试自己的代码好像不太合适的。
况且 专业的测试人员可以很好的搞定这个问题啊。
  • 打赏
  • 举报
回复
在写实现程序之前先写测试然后才是先 --> 在写实现程序之前先写测试然后才实现

传统的单元测试确实额外地写了很多没有什么价值的测试。当一个程序员都写好了实现代码,它立刻写测试来证明自己有错误吗?这是不可能的。它只能写一些将垃圾固定下来当作教条的测试代码,而不是尽可能为系统重构留下灵活性。

而TDD是系统重构的关键保证,是“安全网”。在敏捷开发中最重要的重点之一就是强调开发时只考虑最简单的二三两个属性或者一两个方法的测试,当许多TDD将系统的框架驱动完成时,就重构!通过重构来提高系统性能、改进系统扩展性。如果写传统的单元测试,只在低级的地方给自己设置教条,而在高级的地方没有写下测试代码,与TDD的实际作用正好相反。
  • 打赏
  • 举报
回复
Kent Beck所发明的xUnit系列,是对之前几十年前的自动测试程序极大的简化,仅仅保留了最少、最必要的一点内容(可能最近三、四年才逐渐被变得更加臃肿和庸俗)。因此,如果第一次接触xUnit工具,就掉进传统的单元测试理论里边去了,就是对xUnit系列工具的初衷开了个国际大玩笑。

可是,仅仅抄袭网上的关于单元测试的文章,对许多沽名钓誉的人是个捷径,从来不去研究软件工程以及xUnit工具的背后的历史。单元测试的覆盖率概念,有至少30年的历史,我的书架上就有至少2本十几年前的、我认为现在也很难找到相当水平的关于传统自动化测试书籍,可是它们毕竟都是过时的、有害的书籍,虽然写得太好、那些理论太能用来忽悠人了。
  • 打赏
  • 举报
回复
对于XP开发来说,TDD要求语句的原则是:如果删除一些语句仍然可以让TDD通过,那么这些语句就是多余的。

因此TDD是从必要性这个角度来说测试覆盖率的,是从如何让程序员对测试驱动开发技术入门角度来谈的。注意,测试驱动开发不是时候测试,恰恰相反,它要求程序员习惯用测试来表达自己为什么要写程序,在写实现程序之前先写测试然后才是先(而不是相反)。

因此对于XP开发来说,TDD不是传统的测试。虽然使用单元测试工具,但是它根本不是传统的单元测试。
缪军 2010-06-18
  • 打赏
  • 举报
回复
1、覆盖率:我12楼已经阐述了我的观点;我可以再强调一遍:
物理覆盖100%是没商量的,
逻辑覆盖尽可能接近100%(实际上,许多团队只做到10%,这可能已经很卓越了),
如果逻辑覆盖能达到100%,就没有不合格产品了,
这个准则是传统工业已经确立的,在工厂里,没听说过“片面追求质量”这种说法
2、针对你的观点,你在17楼再次提到“如果这意味着API的改动,自然需要重写单元测试用例”,
正如很多人认为数据库修改,要去修改代码是天经地义的一样,
这些类似的观点都是我一直以来反对的;
3、你对测试的误解恰恰是很多人对测试的最大误解:测试要消耗大量的人力成本,
你见过哪些工厂是靠人工完成测试的?就连测试仪器都不是手工制造的!
4、测试是软件生产能力达到一定成熟阶段的必然需求和必然要解决的问题,
所以测试基本是是自动化的: 无论是单元测试还是UI测试;
格兰特杨 2010-06-18
  • 打赏
  • 举报
回复
看来该讨论已经偏离主题,不再是讨论覆盖率,而是测试方法与开发方法。不过仍然愿意做进一步交流。
--------------------------------------
@microtry: 我不会认为文档就是简单文字的东西,不过在我看来“文档即项目模型,整个开发的策动源”这个描述对我来讲有些抽象,我试图去理解您话后面的意思,看起来有点象是瀑布流程,不过自顶向下的文档驱动与逐步求精的测试驱动开发都是当前业界被接受以及被应用的流程,在我的工作经验中也都有遇到。我目前的理解是只有最适合的流程,没有哪个是放之四海而皆准的。

您说:如果你有10000个受测对象,你难道要求开发人员写10000个测试吗? 你不觉得是重复劳动吗?如果源代码改了呢?岂不是更加令人崩溃?!

首先,这10000个受测对象是如何定义的呢?假定我们讨论的是狭义单元测试中的代码模块,每一个模块的场景与应用上下文都不相同,10000个测试也是应当的。当然,要抽象出他们共同的部分,设计合理的用例,根据模块的复杂度合理规划用例的优先级,以避免你提到的重复劳动。我不太明白您的“源代码改了”意味着什么,如果这意味着API的改动,自然需要重写单元测试用例。这也是我在第一个贴子中提到的"代码评审/重构或代码上下文变更导致的接口变化,多数情况下会带来测试用例的修改;用例越丰富,这部分的工作量越大"。

如果我们讨论的是运行期相关的集成测试,则情况有所不同。很有可能,一个简单的集成测试可能覆盖七成以上的代码模块;但这并不意味着我们就不需要对复杂模块进行单独的代码级的单元测试。想说的是,单元测试与集成测试是相辅相成的关系,正如CMM2CMMI所说,针对不同类型的程序应赋予的权重不同。

最后,据我的理解其实我们说的完全不是同一件事情,您在强调某种流程下文档与集成测试的关系和重要性,而我的贴子在讨论片面追求单元测试覆盖率是否有益。希望您把我的贴子从头读一下,这样也许可以避免重新澄清很多定义上的问题。有概念上的共识才可以开展更有意义的讨论。
缪军 2010-06-18
  • 打赏
  • 举报
回复
如果你有10000个受测对象,你难道要求开发人员写10000个测试吗?
你不觉得是重复劳动吗?如果源代码改了呢?岂不是更加令人崩溃?!

单元测试,测试的是什么?测试的是产品是否达到设计要求,这个标准就是文档,
我所指的文档并不是你所理解的文字的东西,而是项目模型,是整个开发的策动源,
设计人员描述好文档后,文档就能够策动或生成绝大部分的应用程序代码和测试代码,

开发是由文档驱动的,而不是测试,
测试代码和应用程序代码只不过是文档的2个副本,是对同一种应用的2种描述,
一个是实施,一个是观测



格兰特杨 2010-06-18
  • 打赏
  • 举报
回复
@CMM2CMMI: 谢谢理解,这也是我发这篇文章想要让大家达成的共识。:)

@microtry: 您说到:""修改接口会带来测试用例的修改,这是多数情况下不争的事实",遗憾的是这是很多从事测试工作的开发人员的观点或实际处境,其实这是由于不正确的测试方法造成的"

如我们所讨论,测试方法有很多种。这里讨论的,是狭义的单元测试。即,基于Junit或某种类似的工具,类与代码级别的,与运行时无关的白盒测试。在这里我们讨论的接口,是编程接口即事实可调用的API,而非项目文档的描述。测试代码依赖项目文档的情况当然也有,但应该多数是用户行为或信令驱动的集成测试用例,而这样的用例是无法或很难使用工具来统计覆盖率的 - 即使可以,也已经与狭义的单元测试覆盖率不能做为相同的指标。虽然我个人认这集成测试用例在多数情况下更为有效,却还不敢说狭义的单元测试是不正确的测试方法。:) 欢迎继续讨论!

cmm2cmmi 2010-06-17
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 davy_chen 的回复:]
做能够做到的(代码覆盖率能够让多数人做到并被别人看到),片面追求代码覆盖率固然不好,但是单就代码覆盖率本身并没有什么错误。刀其实是中性的,但是到了歹徒手中就成了凶器。测试中各种方法、工具、理论总体来说是好的,但是如果让人错误的使用,就会出现非期望的结果。
[/Quote]

刀论
支持^^
davy_chen 2010-06-17
  • 打赏
  • 举报
回复
做能够做到的(代码覆盖率能够让多数人做到并被别人看到),片面追求代码覆盖率固然不好,但是单就代码覆盖率本身并没有什么错误。刀其实是中性的,但是到了歹徒手中就成了凶器。测试中各种方法、工具、理论总体来说是好的,但是如果让人错误的使用,就会出现非期望的结果。
缪军 2010-06-17
  • 打赏
  • 举报
回复
我在学习测试的知识的时候,很自然的就把OO的思想融入进来,
你们把接口搞错对象了,接口是项目文档
AppCode、TestCode、DB都遵从一个接口
缪军 2010-06-17
  • 打赏
  • 举报
回复
2、"修改接口会带来测试用例的修改,这是多数情况下不争的事实",遗憾的是这是很多从事测试工作的开发人员的观点或实际处境,其实这是由于不正确的测试方法造成的,
测试代码依赖的是项目文档,而不是被测代码,
测试代码的改变只有一个理由:就是项目文档改变了,
所谓单元测试自动化,不是根据被测单元自动生成代码,而是项目文档有能力自动生成测试代码,或者干脆项目文档就具备测试能力,
在整个开发中,项目文档驱动了一切:Code、TestCode、DB
缪军 2010-06-17
  • 打赏
  • 举报
回复
我学习测试方面的知识至今不足2月,但是我发现以我找到的资料看,
国内关于软件测试的水平如同软件生产一样落后,就单元测试而言:
1、覆盖率分:逻辑覆盖和物理覆盖,以现有的手段物理覆盖100%是没问题的,
逻辑覆盖很难达到100%,但这是衡量测试手段的重要指标,这个覆盖率是动态的,
也就是说你的测试工具应当允许随时增加测试数据甚至测试用例以满足覆盖要求,
应该说:任何质量反馈都可能促使我们增加覆盖;

接楼下
加载更多回复(9)
习 题 答 案 习题一答案 一、选择题 1. 软件的主要特性是(A B C)。 A) 无形 B) 高成本 C) 包括程序和文档   D) 可独立构成计算机系统 2. 软件工程三要素是(C D)。 A) 技术、方法和工具  B) 方法、工具和过程  C) 方法、对象和类  D) 过程、模型、方法 3. 包含风险分析的软件工程模型是(A)。 A) 螺旋模型 B) 瀑布模型 C) 增量模型 D) 喷泉模型 4. 软件工程的主要目标是(C)。 A) 软件需求  B) 软件设计  C) 风险分析  D) 软件实 现 5. 下列属于面向对象开发方法的是(A B C D)。 A) Booch   B) UML   C) Coad   D) OMT 6. 软件危机的主要表现是(B D)。 A) 软件成本太高 B) 软件产品的质量低劣 C) 软件开发人员明显不足 D) 软件生产率低下 7. 软件开发方法的主要工作模型有(A B C) A) 螺旋模型 B) 循环模型 C) 瀑布模型 D) 专家模型 8. 软件工程的目标有(A B C)。 A) 易于维护 B) 低的开发成本 C) 高性能 D) 短的开发期 9. 软件工程学的目的和意义是( )。 A) 应用科学的方法和工程化的规范管理来指导软件开发 B) 克服软件危机 C) 作好软件开发的培训工作 D) 以较低的成本开发出高质量的软件 二、 判断题 1. 软件就是程序,编写软件就是编写程序。(×) 2. 瀑布模型的最大优点是将软件开发的各个阶段划分得十分清晰。(×) 3. 结构化方法的工作模型是使用螺旋模型进行开发。(×) 4. 结构化方法和JSP方法都不适合于大型软件的开发。(√) 5. 原型化开发方法包括生成原型和实现原型两个步骤。(×) 6. 面向对象的开发方法包括面向对象的分析、面向对象的设计和面向对象的程序设计。( √) 7. 软件危机的主要表现是软件的需求量迅速增加,软件价格上升。(×) 8. 软件工具的作用是为了延长软件产品的寿命。(×) 9. 软件工程过程应该以软件设计为中心,关键是编写程序。(×) 10. RCP法与RSP法的主要区别是前者采用循环渐进的开发方式,原型将成为最终的产品,而后者将被废弃。(√) 三、简答题 1. 软件产品的特性是什么? 答: ● 软件是一种逻辑产品,具有无形性;  ● 软件产品的生产主要是研制;  ● 软件不存在磨损和老化问题,但存在退化问题;  ● 软件产品的生产主要是脑力劳动;  ● 软件产品的成本非常昂贵,其开发方式目前尚未完全摆脱手工生产方式; ● 软件具有“复杂性”,其开发和运行常受到计算机系统的限制。 2. 软件发展有几个阶段?各有何特征? 答: ① 程序设计阶段。    硬件特征:价格贵、存储容量小、运行可靠性差。    软件特征:只有程序、程序设计概念,不重视程序设计方法。   ② 程序系统阶段。    硬件特征:速度、容量及工作可靠性有明显提高,价格降低,销售有爆炸性增长 。    软件特征:程序员数量猛增,开发人员素质低。   ③ 软件工程阶段。    硬件特征:向超高速、大容量、微型化及网络化方向发展。    软件特征:开发技术有很大进步,但未获得突破性进展,软件价格不断上升,未完全摆脱软件危机。 3. 什么是软件危机?其产生的原因是什么? 答:“软件危机”(Software Crisis)的出现是由于软件的规模越来越大,复杂度不断增 加,软件需求量增大。而软件开发过程是一种高密集度的脑力劳动,软件开发的模式及技术 不能适应软件发展的需要。致使大量质量低劣的软件涌向市场,有的花费大量人力、财力, 而在开发过程中就夭折。软件危机主要表现在两个方面: (1) 软件产品质量低劣,甚至开发过程就夭折。 (2) 软件生产率低,不能满足需要。 4. 什么是软件生存周期模型?它有哪些主要模型? 答:软件生存周期模型是描述软件开发过程中各种活动如何执行的模型。 主要模型包括:瀑布模型、增量模型、螺旋模型、喷泉模型、变换模型和基于知识的模型。 5. 有哪些主要的软件开发方法? 答:主要的软件开发方法有:结构化开发方法、Jackson(JSP、JSD)方法、原型化开发方 法、维也纳开发方法(VDM)和面向对象的开发方法。 6. 软件生命期各阶段的任务是什么? 答:软件生命期瀑布模型分为六个阶段: ● 可行性研究与计划(确定系统的目标和规模,分析项目的可行性); ● 需求分析与规格说明(明确系统的规格和要求); ● 设计(包括概要设计和详细设计,将系统分解为模块); ● 编程(用程序语言实现每个模块,简单容易); ● 测试(发现并改正错误,分为模块测试、集成测试和系统联调三级); ● 运行维护(扩充功能、纠错等)。 习题二答案 一、 选择题 1. 需求分析的主要目的是(B C)。 A) 系统开发的具体方案 B) 进一步确定用户的需求 C) 解决系统是“做什么的问题” D) 解决系统是“如何做的问题” 2. 需求分析的主要方法有(C D)。 A) 形式化分析方法 B) PAD图描述 C) 结构化分析(SA)方法 D) OOA法 3. 面向对象的分析方法主要是建立三类模型,即(D)。 A) 系统模型、ER模型、应用模型 B) 对象模型、动态模型、应用模型 C) E-R模型、对象模型、功能模型 D) 对象模型、动态模型、功能模型 4. SA法的主要描述手段有(B)。 A) 系统流程图和模块图 B) DFD图、数据词典、加工说明 C) 软件结构图、加工说明 D) 功能结构图、加工说明 5. 画分层DFD图的基本原则有(A C D)。 A) 数据守恒原则 B) 分解的可靠性原则 C) 子、父图平衡的原则 D) 数据流封闭的原则 6. 在E-R模型中,包含以下基本成分(C)。 A) 数据、对象、实体 B) 控制、联系、对象 C) 实体、联系、属性 D) 实体、属性、联系 7. 画DFD图的主要目的是(A D)。 A) 作为需求分析阶段用户与开发者之间交流信息的工具 B) 对系统的数据结构进行描述 C) 对目标系统的层次结构进行描述 D) 作为分析和设计的工具 8. 数据字典是数据流图中所有元素的定义的集合,一般由以下四类条目组成(C)。 A) 数据说明条目、控制流条目、加工条目、数据存储条目 B) 数据流条目、数据项条目、文件条目、加工条目 C) 数据源条目、数据流条目、数据处理条目、数据文件条目 D) 数据流条目、数据文件条目、数据池条目、加工条目 9. 在需求分析阶段主要采用图形工具来描述的原因是(B C)。 A) 图形的信息量大,便于描述规模大的软件系统 B) 图形工具能够极好地概括描述一个系统的信息,比文字叙述能够更好地表达重 要的细节 C) 图形能够更加直观地描述目标系统,便于用户理解和交流,有利于开发者与用 户之间达成一致的需求 D) 图形比文字描述简单、形象 二、 判断题 1. 在进行了可行性分析后,需求分析就只需要解决目标系统的设计方案。(×) 2. SA法是面向数据流,建立在数据封闭原则上的需求分析方法。(√) 3. HIPO法既是需求分析方法,又是软件设计方法。(√) 4. 在面向对象的需求分析方法中,建立动态模型是最主要的任务。(×) 5. 加工小说明是对系统流程图中的加工进行说明。(×) 6. 判定表的优点是容易转换为计算机实现,缺点是不能够描述组合条件。(×) 7. 需求分析的主要方法有SD法、OOA法及HIPO法等。(×) 8. 分层的DFD图可以用于可行性分析阶段,描述系统的物理结构。(×) 9. 信息建模方法是从数据的角度来建立信息模型的,最常用的描述信息模型的方法是E-R 图。(√)  10. 用于需求分析的软件工具,应该能够保证需求的正确性,即验证需求的一致性、完整性、现实性和有效性。(√) 三、 问答题 1. 什么是需求分析?需求分析阶段的基本任务是什么? 答: 需求分析是当前软件工程中的关键问题,需求分析阶段的任务是:在可行性分析的基础上,进一步了解、确定用户需求。准确地回答 “系统必须做什么?” 的问题。获得需求规格说 明书。还涉及到软件系统的目标、软件系统提供的服务、软件系统的约束和软件系统运行的环境。它还涉及到这些因素和系统的精确规格说明,以及系统进化之间的关系。 需求分析的基本任务包括: (1) 抽取需求 分析现行系统存在需要解决的问题。获取足够多的问题领域的知识,需求抽取的方法一般有问卷法、面谈法、数据采集法、用例法、情景实例法以及基于目标的方法等;还有知识工程方法,例如,场记分析法、卡片分类法、分类表格技术和基于模型的知识获取等 。 (2) 模拟和分析需求 需求分析和模拟又包含三个层次的工作。首先是需求建模。需求模型的表现形式有自然语言、半形式化(如图、表、结构化英语等)和形式化表示等三种。需求概念模型的要求包括实现的独立性:不模拟数据的表示和内部组织等;需求模拟技术又分为企业模拟、功能需求模拟和非功能需求模拟等。 (3) 传递需求 传递需求的主要任务是书写软件需求规格说明。 (4) 认可需求 就是对需求规格说明达成一致,其主要任务是冲突求解,包括定义冲突和冲突求解两方面。常用的冲突求解方法有:协商、竞争、仲裁、强制、教育等,其中有些只能用人的因素去控制。 (5) 进化需求 客户的需要总是不断(连续)地增长,但是一般的软件开发又总是落后于客户需求的增长,如何管理需求的进化(变化)就成为软件进化的首要问题。对于传统的变化管理过程来说,其基本成分包括软件配置、软件基线和变化审查小组。当前的发展是软件家族法 ,即产品线方法。多视点方法也是管理需求变化的一种新方法,它可以用于管理不一致性, 并进行关于变化的推理。 2. M公司的软件产品以开发实验型的新软件为主。用瀑布模型进行软件开发已经有近十年了,并取得了一些成功。若你作为一名管理员刚加入M公司,你认为快速原型法对公司的软件开发更加优越,请向公司副总裁写一份报告阐明你的理由,切记:副总裁不喜欢报告长度 超过一页(B5)。 参考答案提示: 应先简述瀑布模型的缺点,它已不适宜开发实验型的软件。根据快速原型法的特点,说明它特别适合于开发探索型、实验型的软件。 3. 如何画分层数据流图? 答: 总的原则是:至顶而下,逐层分解(画分层数据流图)。 比较复杂的系统不能画在一张纸上,逐层分解的画法可以控制每一层的复杂度。 顶层:将整个系统作为一个加工,描述系统边界(输入与输出)。 中间层:表示某个加工分解为一组子加工,其中的子加工还需进一步分解。 底层:由不再进行分解的基本加工组成。 4. 加工小说明有哪些描述方法? 答: ● 结构化语言:介于自然语言和形式语言(如谓词逻辑)之间。 ● 结构化英语:通常由外层和内层结构组成。 ● 汉语的情况:精确、简明扼要、文体可以灵活。 ● 判定表:适用于表述比较复杂的加工逻辑,如具有多项选择条件的操作。 ● 判定树:本质上与判定表相同,图形表示更易于理解。 5. 考察下图中子图、父图的平衡。 图1 图2 参考答案: 图1中子图与父图不平衡。子图是父图中加工2的分解,加工2 有输入数据流M和N,输出数据流T,而子图则只有一个输入数据N,却有两个输出数据流T与S。 图2中子图是父图中加工3的分解,虽然表面上加工3只有一个输入数据流“订货单”,而子图却有三个输入数据流,但是如果“订货单”是由“客户”、“账号”和“数量”三部分组成,即有如下数据条目,订货单=客户+账号+数量(2.2.5数据词典),则子、父图平衡。 6. 画出银行取款过程的DFD图。问题描述为:储户用存折取款,首先填写取款单,根据“ 账卡”中的信息检验取款单与存折,如有问题,将问题反馈给储户,否则,登录“储户存款 数据库”,修改相应数据,并更新“账卡”,同时发出付款通知,出纳向储户付款。 参考答案: 7. 常用的软件需求分析方法有哪些? 答: 结构化分析方法(SA)、功能分解法、信息建模法、面向对象的分析方法(OOA)。 习题三答案 一、 选择题 1. 模块的基本特征是(A C)。 A) 外部特征(输入/输出、功能) B) 内部特征(输入/输出、功能) C) 内部特征(局部数据、代码) D) 外部特征(局部数据、代码 ) 2. SD方法的设计总则是(C D)。 A) 程序简洁、操作方便 B) 结构清晰、合理 C) 模块内聚性强 D) 模块之间耦合度低 3. 软件设计的主要任务是(A B D)。 A) 将分析阶段获得的需求说明转换为计算机中可实现的系统 B) 完成系统的数据结构和程序结构设计 C) 完成模块的编码和测试 D) 对模块内部的过程进行设计 4. 设计阶段应达到的目标有(A D)。 A) 提高可靠性和可维护性 B) 提高应用范围 C) 结构清晰 D) 提高可理解性和效率 5. 从工程管理的角度来看,软件设计分两步完成(D)。 A) ①系统分析②模块设计 B) ①详细设计②总体设 计 C) ①模块设计②详细设计 D) ①总体设计②详细设 计 6. 模块独立性准则由以下定性指标来衡量(BD)。 A) 分解度    B) 耦合度    C) 屏蔽性    D) 内聚性 7. 用户界面设计的任务包括(A B C)。 A) 确定用户界面类型 B) 建立任务模型 C) 建立用户模型 D) 建立功能模型 8. 程序设计语言可以分为(B C D)。 A) 面向过程的语言    B) 机器语言 C) 高级语言    D) 汇编语言  9. 程序效率包括(A C D)几个方面的内容。 A) 代码效率     B) 运行效率    C) 存储效率     D) I/O效率 10. SP方法中的基本控制结构有(A B C)。 A) 顺序结构 B) 选择结构 C) 重复结构 D) GOTO结构 11. 内部文档可用注释语言书写,注释语言分为(A B C D)。 A) 序言性注释 B) 描述性注释 C) 功能性注释 D) 状态性注释 12. 为使程序中数据说明更易于理解和维护,必须遵循以下原则(A B C) 。 A) 数据说明的次序应当规范化 B) 一个语句说明多个变量时,各变量名按字母顺序排列 C) 对于复杂的数据结构,要加注释,说明在程序实现时的特点 D) 定义变量名应按字母顺序排列 13. 源程序的效率与(D)阶段确定的算法的效率直接有关。 A) 概要设计 B) 总体设计 C) 单元设计 D) 详细设计 14. 在详细设计翻译转换成源程序代码后,算法效率反映为对程序的哪几个方面的要求 (C D)。 A) 读写速度 B) 代码长度 C) 存储容量 D) 执行速度 15. 提高程序效率的根本途径在于(B C)。 A) 编程时对程序语句进行调整 B) 选择良好的设计方法 C) 使程序最大限度的简洁 D) 选择良好的数据结构与算法 二、判断题 1. 划分模块可以降低软件的复杂度和工作量,所以应该将模块分得越小越好。 (×) 2. 在网状结构中任何两个模块都是平等的,没有从属关系,所以在软件开发过程中常常被使用。(×) 3. 信息隐蔽原则有利于提高模块的内聚性。(√) 4. 中心变换型的DFD图可看成是对输入数据进行转换而得到输出数据的处理,因此可以使 用事务分析技术得到初始的模块结构图。(×) 5. SD法是一种面向数据结构的设计方法,强调程序结构与问题结构相对应。 (×) 6. 所谓结构冲突,是指输入数据与输出数据之间很少或没有结构上的对应关系。通常解决 的办法是:构造一个或者多个中间结构,在输入和输出结构之间进行转换。(√) 7. 当模块的控制范围是其作用范围的子集时,模块之间的耦合度较低。(×) 8. JACKSON方法是以数据流、数据封闭性准则逐层分解的。(×) 9. 程序设计语言的工程特性包括:可移植性、可重用性、可维护性、局部性和顺序性。(×) 10. 项目应用领域是选择语言的关键因素。(√) 11. FORTRAN、Pascal、C语言、PL/1和汇编语言都是科学工程计算可选用的语言。(×) 12. 要用快速原型法开发软件,应选用4GL语言。(√) 13. 提高程序效率的根本途径是选择良好的设计方法、数据结构与算法。(×) 14. 良好的程序设计风格简单说就是高的编程技巧。(√) 三、简答题 1. 模块内联系和模块间联系有哪些种类? 答:块间联系的各种类型的划分,从以下3方面考虑: ● 按块间联系的方式(可分为直接引用与过程调用); ● 按块间共用信息的作用(可分为数据型、控制型与混合型); ● 按块间共用的信息数量多少(信息多联系紧密)。 (1) 块间联系的类型,按照耦合度由大到小分为: 内容型:直接引用另一模块的内部信息; 公共型:两个模块引用共同的全程数据区; 控制型:模块间传送的信息用于控制模块的内部逻辑; 复合型:模块间传送复合的数据结构; 数据型:模块间传送单个数据项。 (2) 块内联系的类型,按照内聚性从小到大分为: 偶然型:模块内部没有必然联系; 逻辑型:逻辑上相似的功能放进一个模块; 瞬时型:将同时执行的语句放在一个模块; 通信型:模块中的各部分引用共同的数据; 顺序型:模块中一部分的输出是另一部分的收入; 功能型: 模块中刚好包含了完成一个基本任务所必需的成分。 2. 分析以下DFD图,说明属于哪种类型的DFD图,并按照相应的变换将其转换为初始的模块 结构图。 参考答案:(略) 3. 下图是修改文件记录的DFD图,请确定其主加工。 解:主加工为:账号、修改、写记录。 4. 按照“降低块间联系,提高块内联系”的设计总则对模块进行修改,具体从哪些方面进 行改进? 解: (1) 尽可能建立功能模块; (2) 消除重复功能; (3) 模块的作用范围与控制范围,即当作用范围为控制范围的子集时,才能获得较低的块间 联系; (4) 模块的大小适当; (5) 模块的扇入扇出数不宜太多。 5. 根据模块的作用范围与控制范围的原则,判定a、b两图的正确性。 解:显然,图a不满足作用范围应与控制范围的原则,模块F的作用范围不在控制范围之内。 图b的模块设计合理。 6. 图a中,模块G为判定,判断涉及到模块B、F、G,请指出设计中的错误,再根据改进模 块图的基本原则,画出1~2个改进方案(不改变模块G的判断关系),并说明是按照哪条基本 原则进行改进的。 解:图b为一个改进方案,将模块G的位置提高,使其作用范围为控制范围的子集,减少模块 之间的联系。 7. 编码阶段的主要任务是什,应交付的结果是什么? 答:编码阶段的主要任务是为每个模块编写程序。即是:将详细设计的结果转换为用某种计 算机语言写的程序——源程序代码。编码阶段应交付的结果是带有“程序内部文档”的、不 再含有语法错误的程序。 8. SP法的自顶向下,逐步求精方法的优点有哪些? 答:此法符合人们解决复杂问题的普遍规律,可提高软件开发的成功率和生产率;而且用先 全局后局部、先整体后细节、先抽象后具体的逐步求精过程,开发出来的程序具有清晰的层 次结构,因此程序容易阅读和理解。这样,程序自顶向下,逐步细化,分解成一个树型结构 。 因此,在同一层次的节点上做细化工作,相互之间没有联系,它们之间的细化工作相互独立 ;在任何一步发生错误,一般只影响它下层的节点,同一层其他节点不受影响;在以后的测试中,也可以先独立地一个节点一个节点地做,最后再集成。这样,程序清晰和模块化,使 得在修改和重新设计一个软件时,可复用的代码量最大。 9. 为了使程序具有良好的设计风格,应注意哪些方面的问题? 答:(1) 标识符应按意取名。 标识符即符号名,包括:模块名、常量名、标号名、子程序名、数据区名、缓冲区名等。 这些名字应能反映它所代表的实际东西,应有一定实际意义,使其能够见名知意,有助于对 程序功能的理解。 (2) 程序应加注释,它分为两类:序言性注释和功能性注释。 序言性注释应置于每个模块的起始部分,主要内容有:①说明每个模块的用途,功能;②说明模块的接口即调用格式、参数描述及从属模块的清单;③数据描述;④开发历史 。 功能性注释是嵌在源程序体中的,用于说明其后的程序段或语句的功能以及数据的状态;也就是解释下面要“做什么”,或是执行下面的语句会发生什么情况;而不是解释下面“怎么做”,因为怎么做常常是与程序重复的,且对读者理解程序没有什么帮助。 10. 样评价程序的执行效率?它与程序清晰性的关系是怎样的? 答:许多程序员往往片面追求效率,其实程序系统的成本不仅包括运行所需的机时,同时还应把程序员及操作员所花费的人力考虑进去。在编程时为追求效率而损害可读性或可靠性,会给以后的维护工作带来困难,所以从整体上看来是不值得的。 此外,还应该认识到,提高程序效率的根本途径在于:选择良好的设计方法、良好的数据结构与算法,而不是靠编程时对程序语句进行调整。 (1) 追求建立在不损害程序可读性或可靠性基础上,要先使程序正确、清晰,再提高程序 效率。 (2) 不能因为贪图效率上的小利,而破坏程序的清晰性。 (3) 让编译程序去作简单的优化。 (4) 提高程序效率的根本途径在于:选择良好的设计方法和良好的数据结构与算法,而不是靠编程时对程序语句做调整。 11. 假定:需要编一个求解一元二次方程根的子程序,加入到现有的子程序库中,供其他程序员使用。要求: (1) 为该子程序写一个序言性注释; (2) 用PASCAL语言或其他语言写出这个子程序(要把根的性质,如:实根、复根、降为一次方程等有区别地通知调用者),并加上描述性注释。 答案:(略) 习题四答案 一、选择题 1. 面向对象程序设计的基本机制(ABC)。 A) 继承 B) 消息 C) 方法 D) 结构 2. 下列属于面向对象的要素有(BCD)。 A) 分类性 B) 抽象 C) 共享 D) 封装 3. 下列选项中属于面向对象开发方法的有(ACD)。 A) Booch B) CAD C) Coad D) OMT 4. 下列属于Coad方法中面向对象的分析模型的层次有(AB)。 A) 主题层 B) 对象层 C) 应用层 D) 接口层 5. 一个类属性依其特征划分,其类型有(ABCD)。 A) 描述型 B) 定义型 C) 派生型 D) 参考型 6. 在进行面向对象分析时,所采用的模型有(ABD)。 A) 对象模型 B) 动态模型 C) 静态模型 D) 功能模型 7. 状态是对象属性的值的一种抽象,它的性质有(AB)。 A) 时间性 B) 持续性 C) 有序性 D) 有穷性 8. 数据流图中的处理必须用对象中的操作来实现常见的操作有(ABCD)。 A) 查询 B) 动作 C) 活动 D) 访问 9. 建立继承关系时所采用的方式有(AC)。 A) 自顶向下 B) 从内到外 C) 自底向上 D) 从复杂到简单 10. 对象是人们要研究的任何事物主要的对象类型有(ABCD)。 A) 有形实体 B) 作用 C) 事件 D) 性能说明 二、判断题 1. 面向对象的的方法是以类作为最基本的元素,它是分析问题解决问题的核心。(×) 2. 类是指具有相同或相似性质对象的抽象,对象是抽象的类,类的具体化就是对象。(√) 3. 继承性是父类和子类之间共享数据结构和消息的机制,这是类之间的一种关系(×)。 4. 多态性增强了软件的灵活性和重用性,允许用更为明确、易懂的方式去建立通用软件, 多态性和继承性相结合使软件具有更广泛的重用性和可扩充性。(×) 5. 面向对象分析,就是抽取和整理用户需求并建立问题域精确模型的过程。(√) 6. 面向对象的设计的主要目标是提高生产效率,提高质量和提高可维护性。(√) 7. 对象模型表示了静态的、结构化的系统数据性质,描述了系统的静态结构,它是从客观世界实体的对象关系角度来描述,表现了对象的相互关系。(√) 8. 面向对象的分析是用面向对象的方法对目标系统的问题空间进行理解、分析和反映。通过对象层次结构的组织确定解空间中应存在的对象和对象层次结构。(√) 9. 类的设计过程包括:确定类,确定关联类,确定属性,识别继承关系。(√) 10. 复用也叫重用或再用,面向对象技术中的“类”,是比较理想的可重用软构件。有三种重用方式:实例重用、继承重用、多态重用。(√) 11. 主题是一种关于模型的抽象机制,它是面向对象模型的概貌,也是关于某个模型要同时考虑和理解的内容,主题起一种控制作用。(√) 12. 面向对象的分析由对象、结构、继承性和基于消息的通信构成。(×) 13. 支持继承性是面向对象程序设计语言和传统程序设计语言在语言机制方面的根本区别。(√) 14. 面向对象的分析过程主要包括三项内容:理解、表达和验证。(√) 15. 面向对象的设计的主要目标是提高生产效率、提高质量和提高可维护性。(√) 三、 简答题 1. 与传统程序设计模式中的过程调用相比,消息传递机制有何本质区别? 答: (1) 消息传递必须给出信道的信息,通常要指出明显的接受方。 (2) 由于接受方是一通信实体,具有保持状态的能力,所以同一发送方在不同时刻向同一 接受方发送同样的信息,可因接受方的当前状态不同而得到不同的结果。 (3) 消息传递可以是异步的,发送方可以不必等待接受方返回信息就可以继续执行后面的操作,因而支持程序的并发和分布执行,而过程调用只能是同步的,本质上是串行的。 2. 阐述面向对象的特征,并做简要的解释。 答: (1) 对象惟一性。 每个对象都有自身惟一的标识,通过这种标识,可找到相应的对象。 (2) 分类性。 是指将具有一致的数据结构(属性)和行为(操作)的对象抽象成类。 (3) 继承性。 是父类和子类之间共享数据结构和方法的机制,这是类之间的一种关系。 (4) 多态性。 是指相同的操作或函数,过程作用于多种类型的对象上,并获得不同的结果。 3. Coad方法主要由面向对象分析OOA和面向对象设计OOD。OOA方法分析过程和构造OOA概念模型的顺序由5个层次组成,请简述这5个层次。 答: (1) 发现类及对象。描述如何发现类及对象。从应用领域开始识别类及对象,形成整 个应用的基础,然后,据此分析系统的责任。 (2) 识别结构。该阶段分为两个步骤。第一,识别“一般-特殊”结构,该结构捕获了识别出的类的层次结构;第二,识别“整体-部分”结构,该结构用来表示一个对象如何成为另一个对象的一部分,以及多个对象如何组装成更大的对象。 (3) 定义主题。主题由一组类及对象组成,用于将类及对象模型划分为更大的单位,便于理解。 (4) 定义属性。其中包括定义类的实例(对象)之间的实例连接。 (5) 定义服务。其中包括定义对象之间的消息连接。 4. 面向对象程序设计有哪些优点? 解:开发时间短、效率高、可靠性高,所开发的程序更强壮。由于面向对象编程的可重用性 ,可以在应用程序中大量采用成熟的类库,从而缩短开发时间,这样程序更易于维护、 更新和升级。继承和封装使得应用程序的修改带来的影响更加局部 化。 5.比较面向对象方法与结构化方法的特点。 解:分析是问题抽象 (做什么),设计是问题求解 (怎么做),实现是问题的解 (结果)。任 何方法学对客观世界的抽象和求解过程都是如此。在问题抽象阶段,结构化方法面向过程, 按照数据变换的过程寻找问题的结点,对问题进行分解。因此,与面向对象方法强调的对象 模型不同,描述数据变换的功能模型是结构化方法的重点。如果问题世界的功能比数据更复 杂或者更重要,那么结构化方法仍然应是首选的方法学。如果数据结构复杂且变换不多, 那么如果以过程主导分析和设计,一旦有系统变更就会给下游开发带来极大混乱。 由于对过程的理解不同,面向过程的功能细分所分割出的功能模块有时会因人而异。而面向 对象的对象细分,从同一问题领域的对象出发,不同人得出相同结论的比率较高。 在设计上,结构化方法学产生自顶向下、结构清晰的系统结构。每个模块有可能保持较强的独立性,但它往往与数据库结构相独立,功能模块与数据库逻辑模式间没有映射关系,程序与数据结构很难封装在一起。如果数据结构复杂,则模块独立性很难保证。面向对象方法抽象的系统结构往往并不比结构化方法产生的系统结构简单,但它能映射到数据库结构中,很容易实现程序与数据结构的封装。 在软件工程基本原则中有一条“形式化原则”,即对问题世界的抽象结论应该以形式化语言 (图形语言、伪码语言等)表述出来。结构化方法可以用数据流图、系统结构图、数据辞典、状态转移图、实体关系图来进行系统逻辑模型的描述;而面向对象方法可以使用对象模型图、数据辞典、动态模型图、功能模型图。其中对象模型图近似系统结构图与实体关系图的结合,动态模型图类似状态迁移图,功能模型图类似数据流图。 6.当重要的对象被发现后,通过一组互相关联的模型详细表示类之间的关系和对象的行为,这些模型从四个不同的侧面表示了软件的体系结构、静态逻辑、动态逻辑、静态物理和动态物理。试描述一下这四种特性。 解:静态逻辑模型描述实例化(类成员关系)、关联、聚集(整体/部分)、和一般化(继承)等关系。这被称为对象模型。一般化关系表示属性和方法的继承关系。定义对象模 型的图形符号体系通常是从用于数据建模的实体关系图导出的。对设计十分重要的约束,如 基数(一对一、一对多、多对多),也在对象模型中表示。 动态逻辑模型描述对象之间的互相作用。互相作用通过一组协同的对象,对象之间消 息的有序的序列,参与对象的可见性定义,来定义系统运行时的行为。 静态物理模型通过模块描述代码的布局。动态物理模型描述软件的进程和线程体系结 构。 习题五答案 一、选择题 1. 下列不是模型元素的是(D)。 A) 关联 B) 聚合 C) 依赖 D) 笔记 2. UML具有扩展性,常见的扩展机制有(BCD)。 A) 修饰 B) 版类 C) 加标签值 D) 约束 3. UML语言支持的建模方式有(ABD)。 A) 静态建模 B) 动态建模 C) 模块化建模 D) 功能建模 4. 下列各种图可用于动态建模的有(ACD)。 A) 状态图 B) 类图 C) 序列图 D) 活动图 5. 下列属于状态的组成部分的有(AB)。 A) 名称 B) 活动 C) 条件 D) 事件 6. UML中包括的事件有(ABCD)。 A) 条件为真 B) 收到另一对象的信号 C) 收到操作调用 D) 时间表达式 7. 属性的可见性有(ABD)。 A) 公有的 B) 私有的 C) 私有保护的 D) 保护的 8. 用例之间的关系有(BCD)。 A) 友元 B) 扩展 C) 使用 D) 组合 9. 应用于通用化约束的方式有(ABCD)。 A) 完整 B) 不相交 C) 不完整 D) 覆盖 10. 消息的类型有(ABC)。 A) 同步 B) 异步 C) 简单 D) 复杂 二、 判断题 1. UML建模语言是由视图、图、模型元素和通用机制构成的层次关系来描述的。 (√) 2. UML是一种建模语言,是一种标准的表示,是一种方法。 (×) 3. 泳道是一种分组机制,它描述了状态图中对象所执行的活动。 (×) 4. 同步消息和异步消息的主要区别是:同步消息的发送对象在消息发送后,不必等待消息处理,可立即继续执行,而异步消息则发送对象必须等待接收对象完成消息处理后,才能继续执行。 (×) 5. 类图中的角色是用于描述该类在关联中所扮演的角色和职责的。 (√) 6. 类图用来表示系统中类和类与类之间的关系,它是对系统动态结构的描述。 (×) 7. 用例模型的基本组成部件是用例、角色和用例之间的联系。 (√)

5,179

社区成员

发帖
与我相关
我的任务
社区描述
软件工程/管理 质量管理/软件测试
功能测试压力测试安全性测试 个人社区 湖南省·长沙市
社区管理员
  • 软件测试
  • 虫无涯
  • 小博测试成长之路
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

欢迎大家加入到软件测试的社区,在这里,希望大家勇于发表自己的看法,欢迎大家分享自己在软件测试工作过程中遇到的问题以及工作经验分享。

1.想转行的小伙伴,遇到问题没有及时回复的,可以私聊小博进行反馈

2.大家对社区有好的建议,都可以在社区发帖进行反馈

推荐大家学习的软件测试入门笔记:软件测试入门学习笔记

试试用AI创作助手写篇文章吧