我实现的对不对?
现在,大家已经完成了第一个题目。这个题目当然是很简单的,但之后随着知识的增多,我们要完成的题目也越发复杂。那么有没有什么方法能检验我们写的代码对不对呢?
手动测试我的代码
回想一下,doctest描述了“当我们在交互模式下这样输入代码,就会得到这样的结果”,那么我们是不是可以打开交互模式,按照doctest的描述输入代码,然后观察结果是不是一致的呢?
答案是肯定的。我们首先打开终端,然后使用cd
命令把当前目录切换到lab00.py
所在的目录下(回忆一下实验讲义前面教你如何切换当前目录)。然后输入python -i lab00.py
。这个命令长得和我们在前面学过的python lab00.py
很像,但多了个-i
。-i
是告诉Python,在使用python lab00.py
执行完lab00.py
后,进入交互模式。而开发Python的程序员之所以采用i
这个字母,是因为它是interactive(交互)的首字母,方便记忆。现在让我们执行python -i lab00.py
。你应该能在终端上看到下面的效果:
$ python -i lab00.py
>>>
接下来的过程就和交互模式一模一样了。你可以对照着doctest,输入twenty_twenty_one()
,然后就会得到
$ python -i lab00.py
>>> twenty_twenty_one()
2021
>>>
这和doctest描述的一模一样,所以你现在可以松口气,相信自己的代码是对的了。如果发现不一样,你就需要看看自己哪里出问题了。
等一等!刚才其实有一个概念的陷阱。现在让我们思考一个问题:为什么说,经过刚才这样一个过程,我们就有理由相信我们的代码是对的呢?
实际上,“相信自己的代码是对的”是一个错误的说法!准确的说,大家只能有理由相信“自己写的代码和doctest所预期的相符合”,进而推论,自己的代码可能是对的。
其实,像这样一个比较代码的实际执行结果和预期结果的过程就叫做测试。这也是“doctest”中test的中文含义。测试不能保证“代码是对的”,只能保证代码在多大程度上与预期相符合。与预期符合得程度越高,我们就更加有信心来相信,我们的代码是对的。
实际上,还有一种检查程序正确的方式叫做形式化验证(Formal Verification),通过规则和逻辑(而非测试样本)来判断程序的正确性。这正是冯新宇老师研究的领域之一。在你之后的学习过程中可能还会进一步接触相关内容。
助教会如何测试我的代码?
对于助教来说,很难一一审查每个人的代码来验证大家写得正不正确,所以我们会采用测试的方法来给大家评分。像我们发布给同学的doctest一般都写得比较简单,所以那些写得不正确的代码也有可能通过doctest,比如像下面这段代码,本来助教希望大家写return a + b
,但有个小机灵鬼直接返回3试图蒙混过关:
def add(a, b):
"""return the sum of a and b
>>> add(1, 2)
3
"""
return 3
但如果我们的测试写得越“详细”,写得不正确的代码就越难蒙混过关。比如像现在:
def add(a, b):
"""return the sum of a and b
>>> add(1, 2)
3
>>> add(3, 4)
7
"""
return 3
因此,助教们会设置一个在线测评网站,用更加“详细”的测试来给大家评分,尽可能防止不正确的代码蒙混过关。我们会在下一节中教大家如何在网站上提交作业,让助教测试你的代码。
本节关于测试的介绍,如果大家理解得不清楚也没关系。甚至这一节提到的方法不用也没关系。重点是记住下一节要讲的提交作业的方法,并知道如何查看自己写的代码拿了多少分。
使用Ok进行自动化测试
随着大家做的题目越来越多、越来越复杂,同学们可能会发现,每当自己写了一段新的代码,就要重新走上面一套doctest的流程,然后嫌手动输入表达式很麻烦。
Python的doctest模块可以自动执行文件中的所有doctest测试,包括你没有完成的函数也会一起测试。 我们可以在终端中输入
python -m doctest lab00.py
,这个命令的内部原理基本上和你之前手动执行的过程一模一样。
我们推荐大家使用Ok客户端来进行自动化测试,ok客户端会帮助我们测试、备份、提交作业。
首先,我们需要登录自己的OJ账号。
在终端中运行python ok --authenticate
,输入自己的OJ用户名和密码完成登录。
$ python ok --authenticate
Performing authentication
Please input your NJU ID: # 输入学号并按下回车
Please input your password: # 输入密码(不会显示在终端上)并按下回车
Authenticated as ......
接着,运行python ok
,Ok会和上面的代码一样执行所有的doctest或其他配置好的复杂测试,并在第一次出错时停止执行。
如果我们使用-i
参数,如python ok -i
,那么出错时就会进入交互模式,方便我们进行排查。
当Ok完成测试后,它会自动帮我们上传一份代码的备份,我们可以在在线测评网站上查看并获取备份。
$ python ok
=====================================================================
Assignment: lab00
OK, version NJU-SICP-v1.2.0
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests
---------------------------------------------------------------------
Doctests for add
>>> from lab00 import *
>>> twenty_twenty_one()
# Error: expected
# 2021
# but got
---------------------------------------------------------------------
Test summary
0 test cases passed before encountering first failed test case