【Lecture 4.3】Test Cases and Exception

2023-05-16

18.1. Introduction: Test Cases

Test Cases以一种可以自动检查的方式表达了对程序的需求。具体地说,测试test断言asserts 程序在其执行的某个特定点上的状态。

我们之前曾建议,在实际编写代码之前,最好先写下关于代码应该做什么的注释。在编写程序之前写下一些测试用例是一个更好的主意。

理由:

  1. 在我们编写代码之前,我们已经知道它应该做什么

  2. ,但是这些想法可能有点模糊。写下测试用例迫使我们对应该发生的事情更加具体。

  3. 当我们编写代码时,测试用例可以提供自动的反馈。实际上,在本书的一些activecode窗口和几乎所有的练习中,您都是这种通过测试用例自动反馈的受益者。我们为那些测试用例编写了代码,但是将它隐藏起来,以避免让您感到困惑,同时也避免泄露答案。您可以从编写自己的测试用例中获得一些相同的好处。

  4. 在较大的软件项目中,每次对代码库进行更改时,都可以运行测试用例集。单元测试Unit tests检查小段代码是否正确实现。功能测试 Functional tests检查较大的代码块是否能正确工作。

    运行测试可以帮助识别某个地方的代码更改破坏了其他代码的正确操作的情况。我们不会在这本教科书中看到测试用例的优势,但是请记住,如果您正在参与一个更大的软件,那么对测试用例的介绍将为基本的软件工程实践奠定基础

现在该学习如何为测试用例编写代码了。

Python provides a statement called assert.

  • Following the word assert there will be a python expression.
  • If that expression evaluates to the Boolean False, then the interpreter will raise a runtime error.
  • If the expression evaluates to True, then nothing happens and the execution goes on to the next line of code.

为什么要编写这样一行代码,它永远不能计算出任何对您有用的东西,但有时会导致运行时错误?由于我们上面所描述的关于自动化测试价值的所有原因。你想要一个测试,它会提醒你,某些你认为是正确的条件实际上并不是正确的。立即注意到这个事实要比在程序执行的更晚的时候出现一些意想不到的结果要好得多,因为您将很难跟踪到代码中出现错误的地方。

为什么不 assert 打印出一些表示测试通过的内容呢? 原因是您不希望让通过的自动化测试的结果塞满输出窗口。您只想知道您的某个测试何时失败。在较大的项目中,使用其他测试用例来代替 assert ,例如python unittest 模块。它们提供了一些输出的摘要,总结了已通过和未通过的测试。在本教材中,我们将使用简单的 assert 语句来进行自动化测试。

要编写一个测试,我们必须知道在程序执行的某个特定点上我们期望的值是什么。在本章的其余部分,我们将看到一些关于 assert 语句的示例,以及关于可能要在程序中添加哪种assert 的想法。。

我们已经了解了如何实现函数的测试。您只需调用test。testEqual中,第一个输入是对函数的调用,第二个输入是正确的值,即函数的正确输出。在这段视频中,我们将考虑哪些测试是可以实现的。

18.6. Writing Test Cases for Functions

return value test

测试函数是否返回正确的值是最容易定义的测试用例。您只需检查在特定输入上调用函数的结果是否产生您所期望的特定输出。它得到一个输入,它产生一个输出,它不会改变任何列表或字典的内容。

Or, to give a more concrete example, if you have a function square, you could have a test case assert square(3) == 9. Call this a return value test.

def square(x):
    return x*x

assert square(3) == 9
assert square(-3) == 9
assert square(0) == 0

检测正确不输出

Side Effect Tests

要测试一个函数是否对可变对象做出了正确的更改,您需要不止一行代码。

首先将可变对象设置为某个值,然后运行该函数,然后检查该对象是否具有期望值。

将此称为副作用测试Side Effect Tests,因为您要检查函数调用是否对可变对象产生了正确的副作用。

下面是一个示例,测试update counts函数(它被故意错误实现)。此函数接受一个名为letters的字符串,并更新与 letters字符串中的 每个字符 在counts_diction中的数目。

'''错误版 每次会把字符先置1再增加,初始计数就不起作用了'''
def update_counts(letters, counts_d):
    for c in letters:
        counts_d[c] = 1
        if c in counts_d:
            counts_d[c] = counts_d[c] + 1

counts = {'a': 3, 'b': 2}
update_counts("aaab", counts)
# 3 more occurrences of a, so 6 in all
assert counts['a'] == 6

# 1 more occurrence of b, so 3 in all
assert counts['b'] == 3

为了进行Side Effect Tests,我们首先创建一个字典,其中包含一些字母的初始计数。 然后我们调用函数update_counts()。 然后,我们测试字典中某些字母的正确计数(在编写测试时,这些正确的计数是手动计算的。为了编写测试,我们必须知道正确的答案是什么)。

'''正确版'''
def update_counts(letters, counts_d):
    for c in letters:
        
        if c in counts_d:
            counts_d[c] = counts_d[c] + 1
        else:
            counts_d[c] = 1


counts = {'a': 3, 'b': 2}
update_counts("aaab", counts)
# 3 more occurrences of a, so 6 in all
assert counts['a'] == 6
# 1 more occurrence of b, so 3 in all
assert counts['b'] == 3

为了处理日益复杂的程序,我们将建议一种称为增量开发incremental development的技术。 增量开发的目的是通过一次仅添加和测试少量代码来避免冗长的调试会话。

如果在进行增量开发之前编写单元测试,随着代码通过越来越多的测试,您将能够跟踪进度。 另外,您可以在增量开发的每个阶段编写其他测试。

unit test = (assert statement).

19.1. What is an exception?

An exception is a signal that a condition has occurred that can’t be easily handled using the normal flow-of-control of a Python program. Exceptions are often defined as being “errors” but this is not always the case. All errors in Python are dealt with using exceptions, but not all exceptions are errors.

异常是一个条件已经发生的信号,不能使用Python程序的常规控制流轻松地处理它。异常通常被定义为错误,但情况并非总是如此。Python中的所有错误都是使用异常处理的,但并不是所有的异常都是错误。

19.2 异常处理Flow-of-contro

为了解释异常的作用,让我们回顾一下Python程序中的正常控制流。在正常操作中,Python依次执行语句,一个接一个。对于三种构造,即if语句、循环和函数调用,这种顺序执行被中断:

  • 对于if语句,只执行几个语句块中的一个,然后流控制跳转到if语句之后的第一个语句。
  • 对于循环,当到达循环的末尾时,流控制跳回到循环的开始,然后使用一个测试来确定循环是否需要再次执行。如果循环完成,则控制流跳到循环之后的第一个语句。
  • 对于函数调用,流控制跳转到被调用函数中的第一个语句,执行该函数,流控制跳转到函数调用后的下一个语句。

看到规律了吗?如果控制流不是完全连续的,那么它总是在改变了的控制流之后立即执行第一个语句。这就是为什么我们可以说Python的控制流是连续的。但是,在某些情况下,这种连续的控制流并不能很好地工作。异常为我们提供了一种方法,使我们可以处理非连续点的异常(异常)。

19.2.1. Raising and Catching Errors 引发捕获错误

try / except控制结构提供了一种处理运行时错误并继续执行程序的方法。 到目前为止,任何运行时错误(例如,要求仅包含3个项目的列表中的第8个项目或除以0)都导致程序执行停止。

With try/except, you tell the python interpreter:

  • 尝试执行一个代码块,即Try子句。

    如果整个代码块执行时都没有任何运行时错误,则只需在try / except语句之后继续执行程序的其余部分即可。

  • 如果在执行代码块时发生运行时错误

    • skip the rest of that block of code (but don’t exit the whole program)
    • execute a block of code in the “except” clause
    • then carry on with the rest of the program after the try/except statement
try:
   <try clause code block>
except <ErrorType>:
   <exception handler code block>

语法相当简单。惟一需要技巧的部分是,在except之后,可以选择指定要处理的错误类型。catch是类异常。如果你写了except Exception:所有的运行时错误都会被处理。如果指定了更受限制的错误类别,则只处理那些错误;任何其他类型的错误仍然会导致程序停止运行并打印错误消息。

举个例子:

try:
    items = ['a', 'b']
    third = items[2]
    print("This won't print")
except:
    print("got an error")

print("continuing")

If we catch only IndexEror, and we actually have a divide by zero error, the program does stop executing.

try:
    items = ['a', 'b']
    third = items[2]
    print("This won't print")
except IndexError:
    print("error 1")

print("continuing")

try:
    x = 5
    y = x/0
    print("This won't print, either")
except IndexError:
    print("error 2")


print("continuing again")
---
报错

还有一个有用的特性。异常代码可以访问包含关于错误确切信息的变量。因此,例如,在except子句中,您可以打印出通常作为错误消息打印的信息,但继续执行程序的其余部分。为此,要在正在处理的异常类之后指定一个变量名。exception子句代码可以引用该变量名。

try:
    items = ['a', 'b']
    third = items[2]
    print("This won't print")
except Exception as e:
    print("got an error")
    print(e)

print("continuing")
---
got an error
IndexError: list index out of range on line 3
continuing

19.3. 👩‍💻 When to use try/except

再举一个例子,假设你从一个网站获取了一些嵌套的数据到一个字典d中。当你试图提取特定的元素时,一些可能会丢失:例如 d may not include a particular key。如果您预期某个特定的键可能不存在,您可以编写一个If …否则请检查并处理。

if somekey in d:
    # it's there; extract the data
    extract_data(d)
else:
    skip_this_one(d)

但是,如果您要提取大量不同的数据,则检查所有这些数据可能会很麻烦。 您可以将所有数据提取包装在try / except中。

try:
    extract_data(d)
except:
    skip_this_one(d)

以这种方式捕获所有异常被认为是糟糕的实践。相反,python提供了一种机制来指定您将捕获的某些类型的异常(例如,仅捕获KeyError类型的异常,当字典中缺少一个键时就会发生这种情况。

try:
    extract_data(d)
except KeyError:
    skip_this_one(d)

image-20200617204516622

19.4. Standard Exceptions

image-20200617204538799

image-20200617204602190

image-20200617204625441

所有的异常都是对象。定义对象的类被组织在一个层次结构中,如下所示。这很重要,因为一组相关异常的父类将为自己及其子异常捕获所有异常消息。例如,一个算术错误异常将捕获自身和所有FloatingPointError、OverflowError和ZeroDivisionError异常。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Lecture 4.3】Test Cases and Exception 的相关文章

  • ASP.NET C# 捕获类中的所有异常

    我知道这不是正确的做法 而且根本不干净 我只是想知道这是否可能 如果我有一个包含很多方法的类 public class Foo methodA methodB methodC 是否可以捕获所有可能发生的异常 而不必在每个方法中编写 try
  • 当整数被零除时,msvc 6 会抛出什么异常?

    我做了一些实验 发现当整数除以零时会引发异常 include
  • OnIdle 事件中的异常不会冒泡

    在我的主窗体上 我订阅了两个事件 Application ThreadException 和 Application Idle 理论上 任何未捕获的异常都应该冒泡到主窗体 但是 如果异常发生在 OnIdle 事件中 则此方法不起作用 系统就
  • 不要在异常堆栈中显示 Python raise-line

    当我在 Python 库中引发自己的异常时 异常堆栈将引发行本身显示为堆栈的最后一项 这显然不是一个错误 在概念上是正确的 但是当您在外部使用代码 例如作为模块 时 它会将重点放在对调试无用的东西上 有没有办法避免这种情况并强制 Pytho
  • 如何获取C#中的异常错误代码

    try object result processClass InvokeMethod Create methodArgs catch Exception e Here I was hoping to get an error code 当
  • Spring - 捕获bean创建异常

    我想在我的代码中捕获 bean 实例化异常 我有什么选择 一种方法是使用基于 Java 的容器配置 Configuration public class AppConfig Bean public SomeBean someBean try
  • SocketTimeoutException:插入 Google 云端硬盘时读取超时 - 是否可以重试?

    如同Java Google Drive SDK File insert execute 上的 SocketTimeoutException https stackoverflow com questions 17583630 java go
  • Windows批处理支持异常处理吗?

    Windows批处理编程支持异常处理吗 如果没有 是否有任何方法可以有效地模拟批处理文件中的异常处理 我希望能够在批处理脚本中的任何 CALL 级别的任何位置 抛出异常 并重复弹出 CALL 堆栈 直到找到活动的 TRY 块 然后 CATC
  • 如何在使用 python 下载时优雅地超时

    我正在循环下载大量文件 其中包含以下代码 try urllib urlretrieve url2download destination on local filesystem except KeyboardInterrupt break
  • 捕获异常:除以零

    当我尝试除以 0 时 以下代码不会捕获异常 我是否需要抛出异常 或者计算机是否在运行时自动抛出异常 int i 0 cin gt gt i what if someone enters zero try i 5 i catch std lo
  • 最佳实践:从属性中抛出异常

    什么时候适合从属性 getter 或 setter 中抛出异常 什么时候不合适呢 为什么 关于这个主题的外部文档的链接会很有帮助 谷歌搜索结果出奇的少 Microsoft 在以下位置提供了有关如何设计属性的建议 http msdn micr
  • java.util.ConcurrentModificationException 和迭代?

    我对数组列表和迭代器非常陌生 这是我第一次遇到这个异常 我有一个 ArrayList u 我想做以下算法 for Character c u if k 1 base case if isAnswer s u get 0 System out
  • 为什么 main() 中的 try-catch 不好?

    有人可以向我解释为什么在 main 方法中使用 try catch 来捕获未处理的异常被认为是不合适的吗 STAThread static void Main try Application Run new Form1 catch Exce
  • 三层 Asp.Net 应用程序中的异常处理

    1 据我了解 在three tierAsp Net应用程序我们应该通过以下方式实现异常处理 a 我们应该把try catch围绕代码块 位于三层中的任何一层 我们希望页面能够从该代码块正常恢复 当此代码生成异常时 b 我们不应该放try c
  • 返回值的复制省略和 noexcept

    我有一个这样的函数模板 template
  • .NET 迭代器包装抛出 API

    我有一个带有 API 的类 它允许我请求对象 直到它抛出一个IndexOutOfBoundsException 我想将它包装到一个迭代器中 以便能够编写更清晰的代码 但是 我需要捕获异常以停止迭代 static IEnumerable It
  • 如何尝试/捕获所有异常

    我正在完成由其他人启动的 UWP 应用程序 该应用程序经常崩溃 我总是陷入困境应用程序 at if global System Diagnostics Debugger IsAttached global System Diagnostic
  • C++,set_terminate 是每个线程本地的吗?

    Should set terminate get terminate在 C 2011 或 C 2003 中为多个线程设置不同的终止异常处理器 例如 如果我有程序并将终止处理程序设置为func 1 然后我启动3个线程 新线程中的终止处理程序是
  • C++ Streambuf 方法可以抛出异常吗?

    我正在尝试找到一种方法来获取读取或写入流的字符数 即使存在错误并且读 写结束时间较短 该方法也是可靠的 我正在做这样的事情 return stream rdbuf gt sputn buffer buffer size 但如果streamb
  • Python 2 的 `exceptions` 模块在 Python3 中丢失了,它的内容到哪里去了?

    一位朋友提到 对于 Python 2 假设您在命令行上的路径环境变量中有它 pydoc exceptions 非常有用 知道它应该可以为他每周节省几分钟的网络查找时间 我自己每周都会用谷歌搜索一次例外层次结构 所以这对我来说也是一个有用的提

随机推荐