单元测试 tornado 应用程序:如何改进错误消息的显示
Unit testing tornado applications: How to improve the display of error messages
我正在使用 unittest 来测试具有多个处理程序的龙卷风应用程序,其中一个会引发异常。如果我运行下面的测试代码加上python test.py
:
# test.py
import unittest
import tornado.web
import tornado.testing
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write('Hello World') # handler works correctly
class HandlerWithError(tornado.web.RequestHandler):
def get(self):
raise Exception('Boom') # handler raises an exception
self.write('Hello World')
def make_app():
return tornado.web.Application([
(r'/main/', MainHandler),
(r'/error/', HandlerWithError),
])
class TornadoTestCase(tornado.testing.AsyncHTTPTestCase):
def get_app(self):
return make_app()
def test_main_handler(self):
response = self.fetch('/main/')
self.assertEqual(response.code, 200) # test should pass
def test_handler_with_error(self):
response = self.fetch('/error/')
self.assertEqual(response.code, 200) # test should fail with error
if __name__ == '__main__':
unittest.main()
测试输出如下:
ERROR:tornado.application:Uncaught exception GET /error/ (127.0.0.1)
HTTPServerRequest(protocol='http', host='localhost:36590', method='GET', uri='/error/', version='HTTP/1.1', remote_ip='127.0.0.1', headers={'Connection': 'close', 'Host': 'localhost:3
6590', 'Accept-Encoding': 'gzip'})
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/tornado/web.py", line 1332, in _execute
result = method(*self.path_args, **self.path_kwargs)
File "test.py", line 13, in get
raise Exception('Boom') # handler raises an exception
Exception: Boom
ERROR:tornado.access:500 GET /error/ (127.0.0.1) 19.16ms
F.
======================================================================
FAIL: test_handler_with_error (__main__.TornadoTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/tornado/testing.py", line 118, in __call__
result = self.orig_method(*args, **kwargs)
File "test.py", line 33, in test_handler_with_error
self.assertEqual(response.code, 200) # test should fail with error
AssertionError: 500 != 200
----------------------------------------------------------------------
Ran 2 tests in 0.034s
FAILED (failures=1)
但是,我希望 unittest 报告第二个测试的错误,而不是失败的断言。此外,'Boom' 异常的回溯出现在单元测试测试报告之前,并且不包含对失败测试函数的引用,这使得很难找到异常的来源。
有什么处理这种情况的建议吗?
提前致谢!
编辑
令我意想不到的是,test_handler_with_error
实际上是做出了 assertEqual
断言,而不是抛出错误。例如,以下代码不执行 self.assertEqual
语句,因此在测试输出中报告 ERROR
而不是 FAIL
:
# simple_test.py
import unittest
def foo():
raise Exception('Boom')
return 'bar'
class SimpleTestCase(unittest.TestCase):
def test_failing_function(self):
result = foo()
self.assertEqual(result, 'bar')
if __name__ == '__main__':
unittest.main()
您可以禁用logging
,只显示测试报告:
logging.disable(logging.CRITICAL)
例如,您可以将其放入
- 创建了 TestCase 子类
- 测试运行器
更多信息How can I disable logging while running unit tests in Python Django?
请记住,CI/CD 系统实际上使用规范化报告,例如junit,然后以更多 readable/elegant 方式展示它 - 更多信息:
- Python script to generate JUnit report from another testing result
- How to output coverage XML with nosetests?
这是预期的行为。您的测试本身断言 return 代码是 HTTP 200,并且由于这是一个错误的正式断言,因此结果是 "failure" 而不是 "error"。您可以像 kwaranuk 的回答中提到的那样抑制日志,但是您会丢失有关实际导致 HTTP 500 错误的原因的信息。
为什么你的代码到达断言,而不是抛出?是因为你的测试代码没有调用HandlerWithError.get。您的测试代码使用 AsyncHTTPTestCase class 提供的 HTTP 客户端开始异步 HTTP GET 操作。 (查看 class 的源代码以获取详细信息。)事件循环一直运行,直到 HandlerWithError.get 通过本地主机套接字接收到请求,并在该套接字上响应 HTTP 500。当 HandlerWithError.get失败,它不会在您的测试函数中引发异常,就像 Google.com 的失败会引发异常一样:它只会导致 HTTP 500.
欢迎来到异步世界!没有简单的方法可以将断言错误和 HandlerWithError.get().
的回溯巧妙地联系起来
我正在使用 unittest 来测试具有多个处理程序的龙卷风应用程序,其中一个会引发异常。如果我运行下面的测试代码加上python test.py
:
# test.py
import unittest
import tornado.web
import tornado.testing
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write('Hello World') # handler works correctly
class HandlerWithError(tornado.web.RequestHandler):
def get(self):
raise Exception('Boom') # handler raises an exception
self.write('Hello World')
def make_app():
return tornado.web.Application([
(r'/main/', MainHandler),
(r'/error/', HandlerWithError),
])
class TornadoTestCase(tornado.testing.AsyncHTTPTestCase):
def get_app(self):
return make_app()
def test_main_handler(self):
response = self.fetch('/main/')
self.assertEqual(response.code, 200) # test should pass
def test_handler_with_error(self):
response = self.fetch('/error/')
self.assertEqual(response.code, 200) # test should fail with error
if __name__ == '__main__':
unittest.main()
测试输出如下:
ERROR:tornado.application:Uncaught exception GET /error/ (127.0.0.1)
HTTPServerRequest(protocol='http', host='localhost:36590', method='GET', uri='/error/', version='HTTP/1.1', remote_ip='127.0.0.1', headers={'Connection': 'close', 'Host': 'localhost:3
6590', 'Accept-Encoding': 'gzip'})
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/tornado/web.py", line 1332, in _execute
result = method(*self.path_args, **self.path_kwargs)
File "test.py", line 13, in get
raise Exception('Boom') # handler raises an exception
Exception: Boom
ERROR:tornado.access:500 GET /error/ (127.0.0.1) 19.16ms
F.
======================================================================
FAIL: test_handler_with_error (__main__.TornadoTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/tornado/testing.py", line 118, in __call__
result = self.orig_method(*args, **kwargs)
File "test.py", line 33, in test_handler_with_error
self.assertEqual(response.code, 200) # test should fail with error
AssertionError: 500 != 200
----------------------------------------------------------------------
Ran 2 tests in 0.034s
FAILED (failures=1)
但是,我希望 unittest 报告第二个测试的错误,而不是失败的断言。此外,'Boom' 异常的回溯出现在单元测试测试报告之前,并且不包含对失败测试函数的引用,这使得很难找到异常的来源。
有什么处理这种情况的建议吗?
提前致谢!
编辑
令我意想不到的是,test_handler_with_error
实际上是做出了 assertEqual
断言,而不是抛出错误。例如,以下代码不执行 self.assertEqual
语句,因此在测试输出中报告 ERROR
而不是 FAIL
:
# simple_test.py
import unittest
def foo():
raise Exception('Boom')
return 'bar'
class SimpleTestCase(unittest.TestCase):
def test_failing_function(self):
result = foo()
self.assertEqual(result, 'bar')
if __name__ == '__main__':
unittest.main()
您可以禁用logging
,只显示测试报告:
logging.disable(logging.CRITICAL)
例如,您可以将其放入
- 创建了 TestCase 子类
- 测试运行器
更多信息How can I disable logging while running unit tests in Python Django?
请记住,CI/CD 系统实际上使用规范化报告,例如junit,然后以更多 readable/elegant 方式展示它 - 更多信息:
- Python script to generate JUnit report from another testing result
- How to output coverage XML with nosetests?
这是预期的行为。您的测试本身断言 return 代码是 HTTP 200,并且由于这是一个错误的正式断言,因此结果是 "failure" 而不是 "error"。您可以像 kwaranuk 的回答中提到的那样抑制日志,但是您会丢失有关实际导致 HTTP 500 错误的原因的信息。
为什么你的代码到达断言,而不是抛出?是因为你的测试代码没有调用HandlerWithError.get。您的测试代码使用 AsyncHTTPTestCase class 提供的 HTTP 客户端开始异步 HTTP GET 操作。 (查看 class 的源代码以获取详细信息。)事件循环一直运行,直到 HandlerWithError.get 通过本地主机套接字接收到请求,并在该套接字上响应 HTTP 500。当 HandlerWithError.get失败,它不会在您的测试函数中引发异常,就像 Google.com 的失败会引发异常一样:它只会导致 HTTP 500.
欢迎来到异步世界!没有简单的方法可以将断言错误和 HandlerWithError.get().
的回溯巧妙地联系起来