软件工程第三周作业(陆遥)

一、理论学习

(一)慕课学习

        本周又重学了一遍《软件工程》慕课的第三章单元测试,学习截图如下:

 

(二)讲义阅读

       本周阅读了《构建之法》讲义的第3章。这章的主题是“两人合作”。

      代码规范分为代码风格规范和代码设计规范。关于代码风格规范,讲义中从缩进,行宽,括号,断行与空白的{}行,分行,命名,下划线,大小写,注释这几个方面着手介绍代码风格规范代码设计规范不仅是程序书写的格式文体,而且牵涉到程序设计,模块之间的关系,设计模式等方方面面。函数是我们写程序基本都会用到的,但让它只做一件事,并且要做好。

      代码复审。定义:看代码是否在“代码规范”的框架内正确解决了问题。代码复审的形式包括自我复审,同伴复审,团队复审。其中最基本的复审手段,就是同伴复审。代码复审简单点来说就是找出编译器检查不出来的bug,比如逻辑上的,算法上的等等。代码复审的最终目的是为了让代码能够更好地实现,更好地满足客户的需求,复审并不是为了针对开发者来找bug的

      结对编程。是一种敏捷开发的的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。输入代码的人称作驾驶员,审查代码的人称作观察员(或导航员)。两个程序员经常互换角色。在结对编程中,观察员同时考虑工作的战略性方向,提出改进的意见,或将来可能出现的问题以便处理。这样使得驾驶者可以集中全部注意力在完成当前任务的“战术”方面。观察员当作安全网和指南。结对编程对开发程序有很多好处。比如增加纪律性,写出更好的代码等。

 

(三)“软件质量与可靠性”相关学习

       本周学习了“软件质量与可靠性”第八版教材的第19章。

      设计质量是指设计师赋予产品的特性。材料等级、公差和性能等规格说明决定了设计质量。如果产品是按照规格说明书制造的,那么使用较高等级的材料,规定更严格的公差和更高级别的性能,产品的设计质量就能提高。在软件开发中,设计质量包括设计满足需求模型规定的功能和特性的程度。符合质量关注的是实现遵从设计的程度以及所得到的系统满足需求和性能目标的程度。

      高质量的软件是一个重要目标,即使最疲倦的软件开发人员也会同意这一点。但是,如何定义软件质量呢?在最一般的意义上,软件质量可以这样定义:在一定程度上应用有效的软件过程,创造有用的产品,为生产者和使用者提供明显的价值。该定义强调了以下三个方面:

      1. 有效的软件过程为生产高质量的软件产品奠定了基础;

      2. 有用的产品是指交付最终用户要求的内容、功能和特征,但最重要的是,以可靠、无误的方式;

      3. 通过为软件产品的生产者和使用者增值,高质量软件为软件组织和最终用户群体带来了收益。

      如果生产了一个存在严重质量问题的软件系统,你将受到损失,因为没有人想去购买。另一方面,如果你花费无限的时间、极大的工作量和高额的资金来开发一个绝对完美的软件,那么完成该软件将花费很长的时间,生产成本是极其高昂的,甚至会破产。

      良好的软件质量不会自己出现,它是良好的项目管理和扎实的软件工程实践的结果。帮助软件团队实现高质量软件的四大管理和实践活动是:软件工程方法、项目管理技术、质量控制活动以及软件质量保证。

 

(四)了解“测试驱动开发”

       测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统的软件开发流程新型的开发方法。它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代码,并加速开发过程。

      测试驱动开发的基本思想就是在开发功能代码之前,先编写测试代码,然后只编写使测试通过的功能代码,从而以测试来驱动整个开发过程的进行。这有助于编写简洁可用和高质量的代码,有很高的灵活性和健壮性,能快速响应变化,并加速开发过程。

      测试驱动开发的基本过程如下:

① 快速新增一个测试;
② 运行所有的测试(有时候只需要运行一个或一部分),发现新增的测试不能通过;
③ 做一些小小的改动,尽快地让测试程序可运行,为此可以在程序中使用一些不合情理的方法;
④ 运行所有的测试,并且全部通过;
⑤ 重构代码,以消除重复设计,优化设计结构。
 

二、实践学习

代码仓库地址:https://gitee.com/luyao92/fourline

(一)生命游戏单元测试

       生命游戏的单元测试是依据慕课“3.4单元测试工具”,一边学一边进行的。相关代码已上传,命名为test_game_map.py,具体代码如下:

from itertools import chain, cycle
from unittest import TestCase
from unittest.mock import Mock, patch, call
from game_map import GameMap


class TestGameMap(TestCase):
    def setUp(self):
        self.game_map = GameMap(4, 3)

    def test_rows(self):
        self.assertEqual(4, self.game_map.rows, "Should get correct rows")

    def test_cols(self):
        self.assertEqual(3, self.game_map.cols, "Should get correct cols")

    @patch('random.random', new=Mock(side_effect=chain(cycle([0.3, 0.6, 0.9]))))
    def test_reset(self):
        self.game_map.reset()
        for i in range(0, 4):
            self.assertEqual(1, self.game_map.get(i, 0))
            for j in range(1, 3):
                self.assertEqual(0, self.game_map.get(i, j))

    def test_get_set(self):
        self.assertEqual(0, self.game_map.get(0, 0), "Cells init to zero")
        self.game_map.set(0, 0, 1)
        self.assertEqual(1, self.game_map.get(0, 0)), "Should get value set by set"

    def test_get_neighbor_count(self):
        expected_value = [[8] * 3] * 4
        self.game_map.cells = [[1] * 3] * 4
        for i in range(0, 4):
            for j in range(0, 3):
                self.assertEqual(expected_value[i][j], (self.game_map.get_neighbor_count(i, j)), '(%d, %d)' % (i, j))

    @patch('game_map.GameMap.get_neighbor_count', new=Mock(return_value=8))
    def test_get_neighbor_count_map(self):
        expected_value = [[8] * 3] * 4
        self.assertEqual(expected_value, self.game_map.get_neighbor_count_map())

    def test_set_map(self):
        self.assertRaises(TypeError, self.game_map.set_map, {(0, 0): 1})
        self.assertRaises(AssertionError, self.game_map.set_map, [[1] * 3] * 3)
        self.assertRaises(TypeError, self.game_map.set_map, [['1'] * 3] * 4)
        self.assertRaises(AssertionError, self.game_map.set_map, [[2] * 3] * 4)
        self.game_map.set_map([[1] * 3] * 4)
        self.assertEqual([[1] * 3] * 4, self.game_map.cells)

    def test_print_map(self):
        self.game_map.cells = [
            [0, 1, 1],
            [0, 0, 1],
            [1, 1, 1],
            [0, 0, 0]
        ]
        with patch('builtins.print') as mock:
            self.game_map.print_map()
            mock.assert_has_calls([
                call('0 1 1'),
                call('0 0 1'),
                call('1 1 1'),
                call('0 0 0'),
            ])

 

       生命游戏的单元测试结果如下:

 

       生命游戏的代码覆盖率结果如下:

软件工程第三周作业(陆遥)_第1张图片

 

(二)计算器单元测试

       计算器程序是第一周完成的作业,在编写单元测试前对原代码进行了完善,主要包括内部变量的命名、运算精度等。单元测试文件命名为test_calculator.py,具体代码如下:

from unittest import TestCase
from calculator import *


class TestCalculator(TestCase):
    def setUp(self):
        self.temp_exp = "3 ^ 2 + ( 8 - 3 ) * 4 / 2"
        self.real_exp1 = del_blank(self.temp_exp)
        self.real_exp2 = "a+1"
        self.real_exp3 = "3+(2-1"
        self.real_exp4 = "1++2"
        self.real_exp5 = "1.2+3.0"
        self.real_exp6 = "1/0"

    def test_del_blank(self):
        self.assertEqual("3^2+(8-3)*4/2", del_blank(self.temp_exp), "error!")

    def test_priority(self):
        self.assertEqual('>', priority('+', "-"), "error!")
        self.assertEqual('<', priority('+', "*"), "error!")
        self.assertEqual('<', priority('+', "/"), "error!")
        self.assertEqual('<', priority('+', "("), "error!")
        self.assertEqual('>', priority('+', ")"), "error!")
        self.assertEqual('<', priority('+', "^"), "error!")

    def test_operation(self):
        self.assertEqual(19, operation(9, 10, '+'), "error!")
        self.assertEqual(5, operation(8, 3, '-'), "error!")
        self.assertEqual(10, operation(5, 2, '*'), "error!")
        self.assertEqual(2, operation(4, 2, '/'), "error!")
        self.assertEqual(9, operation(3, 2, '^'), "error!")
        self.assertEqual("VALUE ERROR", operation(1, 0, '/'), "error!")
        self.assertEqual("VALUE ERROR", operation(0, 0, '^'), "error!")

    def test_calculation(self):
        self.assertEqual(Decimal('19'), calculation(self.real_exp1), "error!")
        self.assertEqual("INPUT ERROR", calculation(self.real_exp2), "error!")
        self.assertEqual("FORMAT ERROR", calculation(self.real_exp3), "error!")
        self.assertEqual("FORMAT ERROR", calculation(self.real_exp4), "error!")
        self.assertEqual(Decimal('4.2'), calculation(self.real_exp5), "error!")
        self.assertEqual("VALUE ERROR", calculation(self.real_exp6), "error!")

 

       计算器的单元测试结果如下:

 

       计算器的代码覆盖率结果如下:

软件工程第三周作业(陆遥)_第2张图片

 

       关于计算器的单元测试,特意选用了“3 ^ 2 + ( 8 - 3 ) * 4 / 2”这个测试用例,原因是其包含了“加”、“减”、“乘”、“除”、“乘方”、“括号”等程序要求的可输入的运算符,最大程度满足对被测试代码的覆盖率。

 

(三)单词检索单元测试

       单词检索程序是第二周完成的作业,在编写单元测试前对原代码进行了完善,主要针对一些检索出现错误情况的修改。单元测试文件命名为test_sample.py,具体代码如下:

from unittest import TestCase
from sample import *


class TestSample(TestCase):
    def setUp(self):
        self.query_file = "test_query.txt"
        self.document_file = "test_document.txt"
        self.query_words = read_query_words(self.query_file)
        self.document = read_document(self.document_file)
        self.sentences = extract_sentence(self.document)
        self.model = build_search_model(self.sentences)

    def test_read_query_words(self):
        self.assertEqual(['language', 'c', 'good', 'yes', 'favo'], read_query_words(self.query_file), "error!")

    def test_read_document(self):
        self.assertEqual("python is a good language. c++ is another one. but my favourite language is java. "
                         "language is", read_document(self.document_file), "error!")

    def test_extract_sentence(self):
        self.assertEqual([['python', 'is', 'a', 'good', 'language'], ['c', 'is', 'another', 'one'],
                          ['but', 'my', 'favourite', 'language', 'is', 'java']], extract_sentence(self.document),
                         "error!")

    def test_build_search_model(self):
        for result in [['python,1/1'], ['is,1/2,2/2,3/5'], ['a,1/3'], ['good,1/4'], ['language,1/5,3/4'], ['c,2/1'],
                       ['another,2/3'], ['one,2/4'], ['but,3/1'], ['my,3/2'], ['favourite,3/3'], ['java,3/6'],]:
            self.assertEqual(True, result in build_search_model(self.sentences), "error!")

    def test_search_word_by_model(self):
        k = 0
        results = ['1/5,3/4', '2/1', '1/4', None, None]
        for word in self.query_words:
            self.assertEqual(results[k], search_word_by_model(word, self.model), "error!")
            k = k + 1

 

       单词检索的单元测试结果如下:

 

       单词检索的代码覆盖结果如下:

 

       关于单词检索程序的单元测试,我选用了内容为“Python is a good language. C++ is another one. But my favourite language is Java. Language is”的查询文档,命名为test_document.txt。待查单词选择了“Language,C,good,yes,Favo”,待查文档命名为test_query.txt。原因是:查询文档中有两句以上的完整句子,有不完整句子,也有单词与符号连接;待查单词有出现多次且在不同句子的单词,有不在文档中的单词,也有不完整的单词。这样就能最大程度满足对被测试代码的覆盖率。

 

三、工作记录

学习时段 学习内容 主要收获 存在问题

 3.2

1830~2100

理论学习

慕课《软件工程》

(清华大学 刘强) 

第3章视频、测验题

 了解单元测试的意义和方法流程。 对TestCase还不太理解。 

 3.3 

1900~2100

理论学习

慕课《Python语言程序设计》

(北京理工大学 嵩天) 

【第3周】基本数据类型

学习了Python基本数据类型和字符串相关函数的应用。 对某些字符串相关函数缺乏实践。

 3.4 

1830~2100

实践学习

生命游戏单元测试

一边学,一边写,熟悉了编写测试用例的流程。  不太理解Mock模块的使用。 

 3.5  

1830~2100

实践学习

计算器单元测试

完善了程序,进行了单元测试。

 3.7

1500~1700

实践学习

单词检索单元测试

完善了程序,进行了单元测试。

build_search_model函数的测试偶尔有失败,

通过改进检索规模得以解决。

 3.8

0800~1000

理论学习

阅读《构建之法》讲义

第3章

 了解了软件开发中的“团队协作”,

以及团队协作的基石——规范。

对讲义里的实例讲解还不太懂。

 3.8

1500~1730

 理论学习

阅读“软件质量与可靠性”

相关内容

从多方面了解了对软件质量的影响因素。  无 

 

 四、总结

       由于对Python语言的学习还处在初级阶段,本职也工作占据了很多时间,感觉这周学习单元测试挺吃力地的,几乎有一半的时间都在查资料,对生命游戏的单元测试也没有完全吃透。虽然单元测试把做出来了,但是是照着自己对单元测试的理解来做的,也不清楚自己的测试流程和测试方法对不对,这是今后肯定要改进的地方。目标还是和之前一样,努力提升Python语言的编程能力,随着课程同步进行学习。

你可能感兴趣的:(软件工程第三周作业(陆遥))