|
5 | 5 | ----------
|
6 | 6 | 问题
|
7 | 7 | ----------
|
8 |
| -You want to write a unit test that cleanly tests if an exception is raised. |
| 8 | +你想写个测试用例来准确的判断某个异常是否被抛出。 |
9 | 9 |
|
10 | 10 | |
|
11 | 11 |
|
12 | 12 | ----------
|
13 | 13 | 解决方案
|
14 | 14 | ----------
|
15 |
| -To test for exceptions, use the assertRaises() method. For example, if you want to test |
16 |
| -that a function raised a ValueError exception, use this code: |
| 15 | +对于异常的测试可使用 ``assertRaises()`` 方法。 |
| 16 | +例如,如果你想测试某个函数抛出了 ``ValueError`` 异常,像下面这样写: |
17 | 17 |
|
18 |
| -import unittest |
| 18 | +.. code-block:: python |
19 | 19 |
|
20 |
| -# A simple function to illustrate |
21 |
| -def parse_int(s): |
22 |
| - return int(s) |
| 20 | + import unittest |
23 | 21 |
|
24 |
| -class TestConversion(unittest.TestCase): |
25 |
| - def test_bad_int(self): |
26 |
| - self.assertRaises(ValueError, parse_int, 'N/A') |
| 22 | + # A simple function to illustrate |
| 23 | + def parse_int(s): |
| 24 | + return int(s) |
27 | 25 |
|
28 |
| -If you need to test the exception’s value in some way, then a different approach is needed. |
29 |
| -For example: |
| 26 | + class TestConversion(unittest.TestCase): |
| 27 | + def test_bad_int(self): |
| 28 | + self.assertRaises(ValueError, parse_int, 'N/A') |
30 | 29 |
|
31 |
| -import errno |
| 30 | +如果你想测试异常的具体值,需要用到另外一种方法: |
32 | 31 |
|
33 |
| -class TestIO(unittest.TestCase): |
34 |
| - def test_file_not_found(self): |
35 |
| - try: |
36 |
| - f = open('/file/not/found') |
37 |
| - except IOError as e: |
38 |
| - self.assertEqual(e.errno, errno.ENOENT) |
| 32 | +.. code-block:: python |
39 | 33 |
|
40 |
| - else: |
41 |
| - self.fail('IOError not raised') |
| 34 | + import errno |
| 35 | +
|
| 36 | + class TestIO(unittest.TestCase): |
| 37 | + def test_file_not_found(self): |
| 38 | + try: |
| 39 | + f = open('/file/not/found') |
| 40 | + except IOError as e: |
| 41 | + self.assertEqual(e.errno, errno.ENOENT) |
| 42 | +
|
| 43 | + else: |
| 44 | + self.fail('IOError not raised') |
42 | 45 |
|
43 | 46 | |
|
44 | 47 |
|
45 | 48 | ----------
|
46 | 49 | 讨论
|
47 | 50 | ----------
|
48 |
| -The assertRaises() method provides a convenient way to test for the presence of an |
49 |
| -exception. A common pitfall is to write tests that manually try to do things with excep‐ |
50 |
| -tions on their own. For instance: |
51 |
| - |
52 |
| -class TestConversion(unittest.TestCase): |
53 |
| - def test_bad_int(self): |
54 |
| - try: |
55 |
| - r = parse_int('N/A') |
56 |
| - except ValueError as e: |
57 |
| - self.assertEqual(type(e), ValueError) |
58 |
| - |
59 |
| -The problem with such approaches is that it is easy to forget about corner cases, such |
60 |
| -as that when no exception is raised at all. To do that, you need to add an extra check for |
61 |
| -that situation, as shown here: |
62 |
| - |
63 |
| -class TestConversion(unittest.TestCase): |
64 |
| - def test_bad_int(self): |
65 |
| - try: |
66 |
| - r = parse_int('N/A') |
67 |
| - except ValueError as e: |
68 |
| - self.assertEqual(type(e), ValueError) |
69 |
| - else: |
70 |
| - self.fail('ValueError not raised') |
71 |
| - |
72 |
| -The assertRaises() method simply takes care of these details, so you should prefer to |
73 |
| -use it. |
74 |
| -The one limitation of assertRaises() is that it doesn’t provide a means for testing the |
75 |
| -value of the exception object that’s created. To do that, you have to manually test it, as |
76 |
| -shown. Somewhere in between these two extremes, you might consider using the as |
77 |
| -sertRaisesRegex() method, which allows you to test for an exception and perform a |
78 |
| -regular expression match against the exception’s string representation at the same time. |
79 |
| -For example: |
80 |
| - |
81 |
| -class TestConversion(unittest.TestCase): |
82 |
| - def test_bad_int(self): |
83 |
| - self.assertRaisesRegex(ValueError, 'invalid literal .*', |
84 |
| - parse_int, 'N/A') |
85 |
| - |
86 |
| -A little-known fact about assertRaises() and assertRaisesRegex() is that they can |
87 |
| -also be used as context managers: |
88 |
| - |
89 |
| -class TestConversion(unittest.TestCase): |
90 |
| - def test_bad_int(self): |
91 |
| - with self.assertRaisesRegex(ValueError, 'invalid literal .*'): |
92 |
| - r = parse_int('N/A') |
93 |
| - |
94 |
| -This form can be useful if your test involves multiple steps (e.g., setup) besides that of |
95 |
| -simply executing a callable. |
| 51 | +``assertRaises()`` 方法为测试异常存在性提供了一个简便方法。 |
| 52 | +一个常见的陷阱是手动去进行异常检测。比如: |
| 53 | + |
| 54 | +.. code-block:: python |
| 55 | +
|
| 56 | + class TestConversion(unittest.TestCase): |
| 57 | + def test_bad_int(self): |
| 58 | + try: |
| 59 | + r = parse_int('N/A') |
| 60 | + except ValueError as e: |
| 61 | + self.assertEqual(type(e), ValueError) |
| 62 | +
|
| 63 | +这种方法的问题在于它很容易遗漏其他情况,比如没有任何异常抛出的时候。 |
| 64 | +那么你还得需要增加另外的检测过程,如下面这样: |
| 65 | + |
| 66 | +.. code-block:: python |
| 67 | +
|
| 68 | + class TestConversion(unittest.TestCase): |
| 69 | + def test_bad_int(self): |
| 70 | + try: |
| 71 | + r = parse_int('N/A') |
| 72 | + except ValueError as e: |
| 73 | + self.assertEqual(type(e), ValueError) |
| 74 | + else: |
| 75 | + self.fail('ValueError not raised') |
| 76 | +
|
| 77 | +``assertRaises()`` 方法会处理所有细节,因此你应该使用它。 |
| 78 | + |
| 79 | +``assertRaises()`` 的一个缺点是它测不了异常具体的值是多少。 |
| 80 | +为了测试异常值,可以使用 ``assertRaisesRegex()`` 方法, |
| 81 | +它可同时测试异常的存在以及通过正则式匹配异常的字符串表示。例如: |
| 82 | + |
| 83 | +.. code-block:: python |
| 84 | +
|
| 85 | + class TestConversion(unittest.TestCase): |
| 86 | + def test_bad_int(self): |
| 87 | + self.assertRaisesRegex(ValueError, 'invalid literal .*', |
| 88 | + parse_int, 'N/A') |
| 89 | +
|
| 90 | +``assertRaises()`` 和 ``assertRaisesRegex()`` |
| 91 | +还有一个容易忽略的地方就是它们还能被当做上下文管理器使用: |
| 92 | + |
| 93 | +.. code-block:: python |
| 94 | +
|
| 95 | + class TestConversion(unittest.TestCase): |
| 96 | + def test_bad_int(self): |
| 97 | + with self.assertRaisesRegex(ValueError, 'invalid literal .*'): |
| 98 | + r = parse_int('N/A') |
| 99 | +
|
| 100 | +但你的测试涉及到多个执行步骤的时候这种方法就很有用了。 |
| 101 | + |
0 commit comments