现代软件工程>第7步 测试与质量:搭建初步结构,增加python脚本 (#767)

* update 第7步 测试与质量:搭建初步结构

* add a script that can merge markdown files under a folder into one, & all the md will be in output folder

* update chapter name

* update chapter16 content, 16.1 木头与软件测试的故事.md 16.2, 16.3...


---------

Co-authored-by: shaopeng
This commit is contained in:
Nathan Bu 2023-05-22 00:06:36 +08:00 коммит произвёл GitHub
Родитель 08a7a705ce
Коммит ac620cd115
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 331 добавлений и 2 удалений

1
scripts/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
output

Просмотреть файл

@ -0,0 +1,62 @@
import os
import shutil
import re
# Define a function named merge_markdown_files that takes a folder path and a file name as parameters and calls copy_img_folders and merge_markdown_content functions
def merge_markdown_files(folder_path, file_name,output_folder="output"):
current_root_dir = os.path.dirname(os.getcwd())
# Use the os.walk() function to iterate over all subdirectories in the folder and store the result in a variable
walk_result = list(os.walk(folder_path))
if os.path.exists(output_folder):
shutil.rmtree(output_folder)
# Loop through each tuple in the list
for dirpath, dirnames, filenames in walk_result:
# Loop through each directory name in the current subdirectory
for dir in dirnames:
# Check if the directory name is "img"
if dir == "img":
# Get the source path of the img folder by joining it with the directory path
src_path = os.path.join(dirpath, dir)
relative_path = os.path.relpath( os.path.abspath(dirpath),current_root_dir)
# print(f'relative_path {relative_path}')
# Get the destination path of the img folder by joining it with the file name and removing the extension
dst_path = os.path.join(output_folder,relative_path, dir)
# Copy the img folder to the destination path using shutil.copytree()
shutil.copytree(src_path, dst_path)
# Use the os.walk() function to iterate over all subdirectories in the folder and store the result in a variable
# Sort the list of tuples by the first element (the directory path)
walk_result.sort(key=lambda x: x[0])
# Open a new markdown file in write mode using the with syntax
with open(os.path.join(output_folder, file_name), "w", encoding="utf-8") as output_file:
# Loop through each tuple in the sorted list
for dirpath, dirnames, filenames in walk_result:
# Sort the list of directory names in alphabetical order
dirnames.sort()
# Sort the list of file names in alphabetical order
filenames.sort()
has_section_name = False
# Loop through each file name in the current subdirectory
for file in filenames:
# Check if the file name ends with ".md"
if file.endswith(".md"):
if not has_section_name:
# Get the folder relative path by using the os.path.relpath() function
section_name = os.path.relpath(dirpath, folder_path)
# Write the section name as a header, followed by a newline character
output_file.write("# " + section_name.replace("\\","\n\n# ") + "\n\n")
has_section_name = True
# Open the markdown file in read mode using the with syntax
with open(os.path.join(dirpath, file), "r", encoding="utf-8") as file1:
# Read the content of the markdown file
content = file1.read()
# Write the file name as the title of the content, followed by a newline character
output_file.write("## " +file.replace(".md","") + "\n\n")
relative_path = os.path.relpath(os.path.abspath(dirpath),current_root_dir)
# print(f'relative_path {relative_path}')
# Replace any image path text in the content with the new location using re.sub()
content = re.sub(r"img\/(\w+\.(JPG|SVG|jpg|svg|png))", f"{repr(relative_path)[1:-1]}/img/\g<1>", content)
# Write the content to the new file
output_file.write(content+ "\n")
# Call the function with the folder path and the file name as arguments
merge_markdown_files("../基础教程/A5-现代软件工程(更新中)", "现代软件工程.md")

Просмотреть файл

@ -24,7 +24,7 @@
- 开发语言掌握能力,比如 C++, Python, C#, Php, Java 等等。
- 设计能力和经验,比如大数据存储与处理经验、复杂系统搭建经验、大用户量的并发访问设计经验、训练神经网络模型的经验、手机应用开发的经验等等。
- 一些著名的服务组件或框架的使用经验,比如 Web 服务器中的 Appache、消息队列中的 RabbitMQ、数据库 MySQL、分布式系统架构 Hadoop 等等。
- 一些著名的服务组件或框架的使用经验,比如 Web 服务器中的 Apache、消息队列中的 RabbitMQ、数据库 MySQL、分布式系统架构 Hadoop 等等。
#### 2. 让技术面试官能看到项目经验

Просмотреть файл

@ -1 +0,0 @@
https://blog.csdn.net/super_vicky/article/details/99460617

Просмотреть файл

@ -0,0 +1,32 @@
<img src="img/Slide1.SVG"/>
上一部分我们综合探讨了软件开发设计和实现的原则和方法论然而在软件产品最终交付给用户之前软件的质量保障QAQuality Assurance和测试Testing是不可或缺的环节。缺乏QA和测试的软件世界是灾难性的。1996年6月4日阿丽亚娜5号运载火箭501在起飞的过程中由于SRI惯性参考系统出现软件故障在发射不到一分钟内爆炸“成就”了一场75亿美元的烟花秀1998年4月20日比尔盖茨在发布会现场演示Windows 98的即插即用功能时连接扫描仪后系统崩溃在无数现场媒体前“展示”了著名的Windows蓝屏。有效的质量保障技术虽然无法清除软件bug但却可以帮助在更早的阶段发现软件缺陷Fail fast从而提升软件的可靠性、稳定性和可用性。
而软件测试是质量保障的核心手段。本章将聚焦于软件测试的应用实践、目标和基本概念,通过实际的工程问题帮助梳理软件测试的脉络,回答以下几个问题:
- 软件测试是什么?
- 测什么,谁来测,怎么测?
- 微软是如何做软件测试的?
<img src="img/Slide2.SVG"/>
### 参考资料
- 《微软的软件测试之道》, Alan Page / Ken Johnston / Bj Rollison著张奭 / 高博 / 欧琼 / 赵勇译,机械工业出版社
- 《构建之法》,邹欣,人民邮电出版社
- 《致命Bug软件缺陷的灾难与启示》金钟河/叶蕾蕾,人民邮电出版社
- 《软件工程实践者的研究方法》Roger S.Pressman/Bruce R.Maxim著郑人杰等译机械工业出版社
- 《软件测试之困:测试工程化实践之路》,肖利琼,人民邮电出版社
- https://www.windowslatest.com/2018/04/25/its-been-20-years-since-windows-98-crashes-live-on-stage-with-bsod/
- https://www.ibm.com/topics/software-testing
- https://en.wikipedia.org/wiki/Software_testing
- https://www.techtarget.com/whatis/definition/software-testing
### TODO list
- 16.1 配图项目背景mobile edge testing
- 本章面向对象:开发人员 or 面试测试人员?

Просмотреть файл

@ -0,0 +1,78 @@
## 木头与软件测试的故事
转眼之间木头已来到自己职业生涯的第8个年头本月初有一位新同事小陈入职木头带领他一起完成了一次线上bug的排查。借由这次机会小陈很快地熟悉了项目中的相关feature定位到了代码中的问题并在木头的帮助下得出了解决方案需要改一行代码然后加两行日志收集的代码方面进行修复情况跟进。
拿定主意新人小陈熟练的打开IDE写好并提交了代码就找到木头兴致勃勃地讲述了想法打算一气呵成地完成代码签入、热修复hotfix、部署和发布完成自己职业生涯的第一个“代码产品化”里程碑。木头见他热情可嘉回想起了自己初入职场的青葱岁月也没有直接泼冷水打趣说道
“好啊不过你这个里程碑肯定早晚会拿到你先别急着合入代码修改先针对这段改动丰富一下单元测试然后最好自己也多测几轮这样再上线比较稳妥。这个feature虽然是新feature不过生产环境目标用户数量也有好几万了。”
“这...需要吗一共就一行代码改动加了个if判断都是局部变量不可能出问题啊。”小陈一脸狐疑的说道。他心想自己以往LeetCode战无不胜写代码经常是一把过这次就这么简单的改动的话完全可以省去测试流程。
“哦,可是这里还加了日志输出,原来是没有这个调用的。”木头一边看着小陈的改动,一边说道。
```java
private void interceptRedirect(String redirectUrl){
...
traceLogger.infoWithArgs(
String.format("Redirect URL: %s", redirectUrl));
...
}
```
```java
// 以下是示例infoWithArgs的底层实现并没有在本次修改中被小陈修改。
public class TraceLogger {
...
public void infoWithArgs(String message, Object... args){
...
info(String.format(message, args));
...
}
...
}
```
“对对,不过这个能出什么问题吗,日志模块的接口到处都在调用,我这里就是把变量的值打印出来而已。而且这个方法貌似已经有一个单元测试在覆盖了,你看这里。”
```java
public void testInterceptRedirect_NoException(String redirectUrl) {
...
interceptor.interceptRedirect("https://www.bing.com/search?q=software+testing");
...
}
```
聊到此处木头直觉事情没有那么简单“你调用日志的时候没有传入参数却调用了infoWithArgs这样会有问题吗”。
“我从上面直接复制粘贴过来的,应该没问题吧?单元测试是通过的。”
两人一起研究起了一下这段代码并对现有的单元测试进行了扩展提供了一些新的数据用例实战了一下结对编程。没想到两人很快发现在入参URL为某些特例包含%a、%b或%c的时候字符串格式化语句会出现异常 `MissingFormatArgumentException` 报错,导致整个业务流中断。而这个所谓的特例,在这个业务场景中和代码逻辑中频次很高,可能会导致线上数千用户的体验中断。
```java
@Test
public void testInterceptRedirect_NoException(String redirectUrl) {
...
interceptor.interceptRedirect("https://www.bing.com/search?q=software+testing");
// 新增的用例会在原有代码上触发 `MissingFormatArgumentException` 异常
interceptor.interceptRedirect("https://www.bing.com/search?q=%e5%be%ae%e8%bd%af%e4%b8%ad%e5%9b%bd");
...
}
```
小陈惊出一身冷汗自己心心念念的职业里程碑差点演变成大型翻车现场本来是打算修复一个线上问题没想到差点制造出新问题。这时的他再看木头不由觉得木头周身有一圈佛光是上天派来拯救他的。“看来一行代码改动也要仔细研究而测试是很好的代码问题的检验手段需要多下功夫研究研究。”小陈顿了顿然后激动地说“软件bug的代价太大宁可错杀不可放过。”小陈又燃了起来不过这次却让木头很是欣慰听的频频点头。
“哈哈你讲的挺逗确实如此bug能咱们自己发现修掉就不要让客户帮咱们体验。从某种程度上来说编程是对逻辑复杂性的管理。咱们的项目代码行数是百万级别的逻辑复杂情境和用例非常多每一处修改都有可能牵一发而动全身。全面的测试可以帮助我们在更早的阶段评估代码修改的影响。”
木头接着说“其实你不用后怕咱们的代码合入之后还会经过层层检测。代码合入主分支之后还会经过bvt测试、更全面的集成测试热修复上线之前还会经过验收测试、回归测试以及压力测试再部署到测试环境进行内部的自测。之后都没问题才可能发布到预生产环境、生产环境。所以你这个问题大概率能够在上到预生产之前被拦截下来。我估计集成测试都过不了哈哈。”
小陈挠头附和打个哈哈,心想,这些你不早说,原来还有这么一大堆测试。
又聊了几句,两人看时间不早了,就由小陈着手把代码修复完整后提交了,等待其他同事帮忙评审,就先下班了。
“还有一条规则,周五下午坚决不发版。下周见!”木头大手一挥,消失在大楼转角。
今天发生的事情对小陈触动很大回家后他依然在思考为什么自己当时写代码时没有想到这个特例corner case木头说的“全面的测试”又如何理解其具体含义一方面他今天只接触了单元测试而木头还提到了其他很多种类的测试。另一方面测试团队似乎很重要可以帮忙发现很多问题而自己作为开发人员、代码修改的第一作者和“全面的测试”之间的关系是什么是否软件质量要依赖于测试团队的工作
最终,如果有了“全面的测试”,是不是软件质量就可以高枕无忧了?
带着这样一个又一个问题,小陈查了查资料,看到一句“测试是为发现错误而执行程序的过程”,还没来得及梳理出脉络,就感觉困意袭来,于是洗漱睡觉,结束了充实的一天。

Просмотреть файл

@ -0,0 +1,27 @@
## 故事分析-软件测试的必要性和复杂性
软件测试的重要性是和软件所服务的用户数量正相关的越是成熟的公司越是大型的软件就越需要完善测试层层把关。软件测试的复杂性会随着软件本身的复杂性的上升而上升。如果是简单明确的程序或者脚本自测验证即可而对于例如微软内部的Windows或者Office大型产品线测试的计划需要在产品设计阶段就介入在架构和组件层面要考虑软件的可测试性确保Testable并设计和逐步建立完善的、全方位的测试体系来保障问题尽早被发现Fail fast
对于微软这样用户规模很大(亿级别)的公司来讲,任何一次“小的”软件质量事故,哪怕是只有万分之一的概率出现,也可能会影响成千上万的用户,破坏体验、口碑,甚至演变成为公关事件,影响公司声誉,造成巨大的商业损失。
既然如此,什么能为软件产品的上线、版本更新带来信心呢?测试这一活动,通过衡量实际情况与预期之间差距,正是增加对软件质量信心的关键活动。团队在上线前,看到一份“测试通过”的测试报告,自然会更放心一点。
<img src="img/Slide3.SVG"/>
### 测试与质量保证
从刚刚木头和小陈的故事当中,我们也可以体会到这点:代码有单元测试覆盖,所以会小陈会觉得自己的修改有保障,获得了“迷之自信”;但实际情况是,代码依然存在严重问题。而小陈后来反思的时候,看到了书上的"测试是为发现错误而执行程序的过程",也得到了一些启发。这些共同说明:
1. 开发人员的自测是有很大局限性的。
2. 仅靠测试是无法保障产出高质量软件。
3. 从心理学、活动意图角度上讲,测试不应该是为了增加信心的,不能让测试变成“自卖自夸”;而是应该以一种略带质疑的审视,假定软件有问题的前提下,努力的把问题找出来。这样的测试才可能会更有成效、更有意义。
故事中,小陈认为代码的修改量很小,并且是局部变量的改动,“问题不大”,忽视了所谓的“边界”情况。根据实践中的经验,软件开发中出现的问题往往不必和精巧的设计、核心的业务逻辑有必然联系,而更多出现在被疏忽的“边缘”环节上。而测试就是要发现软件错误和异常情况。
当今时代编程已经发生了更多的演化:我们有越来越多的类库、别人写好的方法可以调用,有越来越多的“轮子”、“巨人的肩膀”来加速功能实现。这就意味着,一行代码可能暗藏着很深的调用栈和很长的调用链条。木头作为资深的工程师,意识到即使是小的改动也可能引入问题,尤其是在复杂的软件系统、数据场景中。当软件足够复杂,“简单”的改动已经非常不可信,务必进行相应的测试,以避免潜在的问题。
木头作为经验丰富的同事,担任着指导和教育小陈的角色。他强调了测试的重要性,并解释了测试的流程和不同阶段的测试类型。在软件开发中,测试团队在保证软件质量方面的重要作用。然而质量并不是测试团队的“锅”,软件质量保障是整个团队的责任。
要做好测试,需要了解和运用一系列的测试知识和工具。木头也提到,不仅仅有单元测试,还有其他类型的测试,如集成测试、回归测试、压力测试等,并解释了这些测试环节在保证软件质量方面的作用:在不同层次和环境中验证软件的正确性和稳定性。
总的来说,软件测试发展至今,体系庞大、功能也很强大,但它不是万能的。它是确保软件质量的关键环节之一。开发人员应该积极参与测试,并与测试团队合作,打造体系,诚实勇敢地去发现问题、重视问题、面对问题、评估问题和最终解决问题,共同提高软件的质量和可靠性。

Просмотреть файл

@ -0,0 +1,101 @@
## 什么是软件测试
软件测试似乎并没有所谓的“权威”的定义,说法众多,比较常见的说法是,软件测试是一种实际输出与预期输出之间的审核或者比较的过程。测试的意图是验证软件的行为,进而发现会导致系统失败的问题。结合前文,“测试是为发现错误而执行程序的过程”,提炼两个关于测试的重点:
- 测试过程体现了实际输出与预期输出间的比较。
- 要带着质疑的视角,提供客观、独立的结论,暴露软件实施的风险。
从时间要求上,测试这个过程可以很简短,也可以持续到所有利益相关者都满意为止。
### 以问题为导向
问题是测试的最重要的产出之一谈及测试我们先全面的认识一下软件的“问题”。我们一般习惯称软件的问题为“Bug”不同语境下也可以用为“Defect缺陷”、“Exception异常”、“Fault错误”和“Issue问题”等代指他们分别强调了问题的不同方面或者不同部分。以下是一些由表及里的概念
| 概念 | 解读 |
| ------------------- | -------------------------------------------------- |
| Symptom 症状 | 问题的表征,如崩溃、严重的卡顿 |
| Issue 问题 | 一般是问题的表象的描述,代表了用户对这个问题的感知 |
| Defect 缺陷 | 可能指逻辑上的疏漏、不足之处和软件设计层面的问题 |
| Exception 异常 | 强调“和预期不符”,不一定是真的问题 |
| Fault/Error 错误 | 问题在程序层面的表现,如段错误 Segment Fault |
| Root Cause 根本原因 | 错误的根源,即导致代码错误的根本问题 |
从问题表象到根本原因之间的距离可长可短一个程序的崩溃、请求的失败一般首先反映在用户体验上开发团队可以将问题定位到一段出错的代码中然而一段代码的错误或异常可能是由其他代码导致的比如Out of memory内存溢出OOM问题往往报错的代码只是压倒骆驼的最后一根稻草问题的根本原因可能隐藏在整体的软件内存管理、资源利用效率和方式上。再发散一点一个软件问题的根本原因可能和软件的工程流程、发布流程、团队管理甚至企业文化都有些许联系。
微软内部的产品组会在临近上线前组织“Bug-bash”打虫子大会召集开发团队的所有人产品、开发、测试全都来对产品进行“Self-host”自用自测发现问题就报告出来。这样做有很多好处一方面鼓励大家多多用自己开发的软件增强主人翁精神另一方面团队发现问题和解决问题的人坐在一个屋子里、或者处在一个会议中缩短问题解决的周期效率很高。
一般用于描述一个问题的报告称为“Bug report”缺陷报告。它通常由以下几个主要部分组成以帮助开发团队定位和修复问题
1. 标题:
Bug Report的标题应简明扼要地概括问题使读者能够快速了解报告的主要内容。
2. 描述Description
描述部分详细说明了bug的情况包括以下内容
- 测试环境和准备工作:描述进行测试时所用的软件环境、硬件设备、配置等信息,以及为了测试而进行的准备工作。
- 测试步骤:清晰列出每一步所执行的操作和动作,包括输入的数据、点击的按钮、导航的路径等。
- 实际发生的结果:记录在执行测试步骤后实际观察到的结果,可能包括错误信息、异常行为、崩溃等现象。
- 应该发生的结果:根据规范和用户的期望,描述在特定情况下应该发生的预期结果。
3. 附加材料:
如果有必要Bug Report可以附带其他补充材料例如相关联的bug编号、输出文件、日志文件、调用堆栈的列表、截屏等。这些附件或链接有助于进一步的问题分析和复现。
4. 其他字段:
在Bug Report中还可以包含其他字段用于提供更多信息如严重程度Severity、功能区域等。这些字段有助于对问题进行分类、评估和优先级排序。
<img src="img/Slide4.SVG"/>
Bug Report是一个重要的工具它能够帮助测试团队和开发团队之间进行有效的沟通和合作以及保障软件质量的提升。编写清晰、准确的Bug Report有助于减少问题的误解和漏洞提高问题解决的效率和质量。
那么,测试是通过怎样的过程和方式把问题挖掘出来的呢?
### 测试的分类:测什么和怎么测
软件测试的被测对象被称为Software Under TestSUT。然而根据具体的测试目的和关注点的不同测试可以分为如下几类
1. 功能验证
- **功能测试**Function test测试软件系统的设计功能是否符合规格要求。
- **结构测试**Structure test白盒测试中对模块内部结构进行测试验证代码的逻辑正确性和覆盖率。
- **可用性测试**Usability test从使用的合理性和方便性等角度进行测试发现人为因素或使用上的问题。
- **配置测试**Configuration test测试软硬件系统平台对软件的支持和兼容性。
2. 性能验证
- **性能测试**Performance test验证系统是否满足规格中规定的性能要求如响应时间、吞吐量、处理精度、缓冲区大小等。
- **负载测试**Load test用满负荷长时间测试系统的稳定性此时性能可以忽略
- **压力测试**Stress test验证系统在超负荷和异常环境下的运行能力和稳定性此时性能可以忽略
- **可靠性测试**Reliability test评估系统的平均失效时间MTBF和故障停机时间MTTR
3. 辅助测试
- **兼容性测试**Compatibility test测试不同版本间的兼容性尤其关注文件存储/读取的兼容性,包括向下兼容和交叉兼容。
- **安全测试**Security test验证系统的安全性确保系统对于潜在攻击的防护措施有效。
- **可访问性测试**Accessibility test验证系统对于聋哑人、盲人等特殊用户的易用性和无障碍访问性。
- **本地化/国际化测试**Localization test主要验证软件在不同地区和语言环境下的本地化和国际化适配性特别关注界面文字的正确性。
<img src="img/Slide12.SVG"/>
这些测试分类方式有助于测试团队根据不同的测试目标和需求,制定合适的测试策略和执行计划。此外,测试可以按照如下几个方面进行分类:
#### 按照测试设计的方法分类
- **黑盒测试**通过观察系统的输入和输出以及对系统功能的期望行为进行测试不需要了解系统内部的实现细节。黑盒测试在设计的过程中把软件系统当作一个“黑箱”无法了解或使用系统的内部结构及知识。也可以说是“Behavioral Test Design”从软件的行为而不是内部结构出发来设计测试。
- **白盒测试**:基于对系统内部结构和代码的理解,设计测试用例来验证系统的逻辑正确性和代码覆盖率。在设计测试的过程中,设计者可以“看到”软件系统的内部结构。“白盒”并不是一个精确的说法,因为把盒子涂成白色,同样也看不见箱子里的东西。
- **灰盒测试**:结合黑盒测试和白盒测试的特点,既关注功能验证,又考虑系统内部的结构和实现。
黑盒测试更接近用户视角,可以作为整体系统测试的一部分,验证系统在各种使用情况下的功能和行为。白盒测试对测试人员的要求更高,有时需要侵入系统、进行访问和修改,但更接近代码层面,可以发现潜在的逻辑错误、边界条件问题和代码覆盖不足的情况。“灰盒测试”还不是一个很流行的测试方法,处于“灰色地带”,好比无法窥见全貌却可以从某一个侧面或切面了解系统内部情况,同时观察外部行为,可能是一种先定条件下的测试(比如结合逆向工程的测试),对测试人员的综合能力要求更高。
#### 按照测试的实施方法分类
- **自动测试**:利用自动化工具和脚本执行测试,提高测试效率和一致性,适用于重复性较高的测试任务。
- **手动测试**:通过人工操作和观察进行测试,适用于需要人的主观判断和复杂交互的测试场景。
测试并不一定要全部依赖于自动化测试,也不一定自动化越多越好;手动测试在某些情况下仍然具有必要性和重要性:例如探索性测试这种灵活性和创造性的测试方法在自动化测试中难以实现;手动测试能够模拟真实用户的操作和交互,更好地评估系统的用户体验;在某些情况下,系统的变动频繁或测试需求经常变化,手动测试具有更高的灵活性和适应性,能够快速调整测试策略和执行方式。
#### 按照测试的范围分类
- **单元测试**:对软件的最小单元(如函数、方法)进行测试,验证其独立性和功能正确性。
- **集成测试**:测试不同模块之间的接口和交互,确保模块能够协同工作。
- **系统测试**:以整个系统为被测对象进行测试,验证系统在各方面的功能和性能。
- **验收测试**:由最终用户或客户进行的测试,以确认软件是否满足其需求和期望。
### 谁来测:测试人员的职业素养

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 56 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 29 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 42 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 506 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 56 KiB

Просмотреть файл

@ -1,3 +1,10 @@
$$
软件 = 程序 + 软件工程 \tag{18.1}
$$
$$
软件的质量 = 程序的质量 + 软件工程的质量 \tag{18.2}
$$
### 运行期质量需求
@ -18,3 +25,20 @@
- 可测试性Testability对软件测试以证明其满足需求规范的难易程度。
- 可维护性Maintainability当需要修改缺陷、增加功能、提高质量属性时定位修改点并实施修改的难易程度
- 可移植性Portability将软件系统从一个运行环境转移到另一个不同的运行环境的难易程度。
## 为什么软件质量保障重要
在微软质量保障也被认为是Engineering Excellence EE (可以翻译为卓越软件工程)的一部分。
客户对产品的评定是信任的指标,必须赢得并持续保持。微软云质量工程是一项全公司努力,旨在确保微软云成为全球最可靠的分布式云。
卓越是一种通过训练和习惯获得的艺术。
我们之所以行为正确,不是因为我们有美德或卓越,而是因为我们行为正确,因此才有了美德或卓越。
我们反复做的事情塑造了我们,因此卓越不是一种行为,而是一种习惯。——亚里士多德
质量和卓越一样,不是你可以简单发货和勾选清单的东西。它需要在开发和服务生命周期中进行持续的、习惯性的投入。一个人、一个团队不能单独对质量结果负责。我们所有人都要对质量结果负责。
为了赢得客户的信任,我们必须在整个开发和服务生命周期中专注于客户。这始于任何代码编写之前,理解和衡量客户的目标,并将它们用于设计、实施、改进和运营我们的服务。