4

我已经阅读了一些关于何时使用断言以及何时使用异常的信息。我不清楚的是为什么?

例如:断言仅用于检测编程错误,也就是错误。相比之下,异常可以指示其他类型的错误或“异常”情况;例如无效的用户输入、丢失的文件、堆满等等。

现在:“断言仅用作检测编程错误(也称为错误)的一种手段” - 现在所有断言都被异常替换了,这有什么危害?例外会做同样的事情吗?

“断言仅用于调试目的,不应发生其触发条件。” - :现在好吧,如果我使用异常然后执行,那么永远不会抛出异常

据我了解,异常可以做所有断言,除非它们不能被禁用。禁用断言是应该使用它们的唯一原因吗?

是否有理由使用它们而不是何时使用它们?

谢谢

4

7 回答 7

3

测试用例使用断言来确保您构建的内容在未来不会呈现出意外的结果。例如,您可以断言以确保在错误输入时引发异常。

很多时候,在编程中更改一件事意味着您必须更改其他代码。断言确保您所做的更改不会破坏您过去编写的代码。

例外是好的。它们是预期的并通过异常处理。例如,您有登录名和密码错误的例外情况。

您可以断言,如果登录名或密码不正确,则会引发预期的异常。

断言包含三个主要内容。你正在测试什么(例如函数名,ie sign_in),输入什么(函数参数ie {'email': 'john@example.com', 'password': hashlib.md5('my_password')}),输出什么(assertTrue('user_name' in response, 'Expecting user_name to be in response!'))。

异常是代码中正常的、合乎逻辑的选择。断言是用于确保遵循逻辑路径的测试。

根据 python unittest framework,您可以断言抛出异常:

import random import unittest

class TestSequenceFunctions(unittest.TestCase):

    def setUp(self):
        self.seq = range(10)

    def test_shuffle(self):
        # make sure the shuffled sequence does not lose any elements
        random.shuffle(self.seq)
        self.seq.sort()
        self.assertEqual(self.seq, range(10))

        # should raise an exception for an immutable sequence
        self.assertRaises(TypeError, random.shuffle, (1,2,3))


    def test_choice(self):
        element = random.choice(self.seq)
        self.assertTrue(element in self.seq)

    def test_sample(self):
        with self.assertRaises(ValueError):
            random.sample(self.seq, 20)
        for element in random.sample(self.seq, 5):
            self.assertTrue(element in self.seq)

if __name__ == '__main__':
    unittest.main()
于 2013-08-07T19:27:31.350 回答
2

断言被设计为有选择地关闭,默认情况下它们是关闭的。当存在不应该出现的情况时,您应该使用它们,但如果您确实需要,可以检查它们。认为它们比例外更例外。

异常及其检查始终处于打开状态。尽管异常,但它们仍然可能随时发生。

断言可以检查编码错误,一旦你的程序没有错误,就不需要它们。由于可能不受您控制的值(例如输入)可能会触发异常。

于 2013-08-07T20:03:33.173 回答
1

与测试代码相反,工作代码中的断言用于检查提供给代码的值是否正确。如果值错误,则抛出断言异常。

您可以编写自己的代码来测试这些值并抛出您自己选择的异常。

断言易于使用,并且与日志记录一样,可以在经过彻底调试的生产代码中关闭。此外,任何阅读代码的人都知道为什么会有测试,而无需考虑它。所以它节省了他们的时间。(当你回去阅读你两年前写的代码时,它也会节省你的时间。)

无论哪种方式都有效。

于 2013-08-07T19:32:50.553 回答
1

许多程序员将断言转换为发布代码中的异常检查。或者他们可能会使用两种不同的断言来转换一种而不是另一种,如果其中一些恰好对性能非常敏感。

这是防御性编程的一部分。断言应该记录不可能的条件。然而,现实生活中的程序员知道,由于未经测试的代码路径、系统库中的错误或硬件错误,有时确实会发生不可能的情况。

将断言转换为异常通常没有什么危害。在 Java 中可能会发生一些危害,它可能会在以前没有的方法中引入新的异常类型。另一个危害可能是转换后的断言可能位于需要非常高性能的循环中,并且断言检查可能会使它减慢太多。

于 2013-08-07T19:34:18.267 回答
0

我认为主要区别在于断言允许您看到问题比异常更早发生。因此,它为您提供了一个更早的执行点,以尝试对其做一些事情(或者可能什么都不做——让它失败)。因此,如果您想在真正糟糕的事情发生(抛出异常)之前查看执行情况,您可以使用它们。

我能想到的一个戏剧性的类比是那些联盟号运送到国际空间站的火箭,偶尔你会听到自动火箭在一开始就偏离了轨道并立即触发了它的“自毁”。我猜这有点像他们用来确定火箭航向是否正确的断言(如果它是一个例外 - 到可以抛出的时候火箭可能已经击中了什么东西)。

于 2013-08-07T19:36:32.290 回答
0

断言被设计为有选择地关闭,默认情况下它们是关闭的。当存在不应该出现的情况时,您应该使用它们,但如果您确实需要,可以检查它们。认为它们比例外更例外。

异常及其检查始终处于打开状态。尽管异常,但它们仍然可能随时发生。

断言检测编码错误。一旦您的程序没有错误,就不需要它们并且可以关闭它们。异常会检测到不正确的使用或输入,并且无法安全关闭。

于 2013-08-07T20:05:14.583 回答
0

我在生产代码中看到了两个断言用例:

在方法开始时,您通常会检查给定参数是否有效。对于公共方法,您将使用 if 语句和异常。对于私有方法,您将使用 assert 进行类似的检查。这个想法是为了避免在测试时(或当出现问题时)在生产中进行冗余检查,您可以激活断言来进行一些双重检查。

使用断言的另一个原因是记录以下代码中使用的假设。像这样,某些值在这里被认为永远不会为空。

这里有一些示例代码

public class Exampel {
    public publicMethod(final Integer i) {
        if (i == null) {
            throw new RuntimeException("i should not be null");
        }

        privateMethod(i):
    }

    private privateMethod(final Integer i) {
        assert i != null;

        // do something
    }
}

您不想多次检查 i 是否为 null。你只会假设它privateMethod被正确使用。您还向任何阅读您的代码的人提示将 null 传递给privateMethod是错误的做法。

于 2013-08-07T20:29:45.733 回答