我有一些像这样的功能:
URL = 'http://localhost:8080'
def func():
response = urlopen(URL)
return process(response)
我想用unittest测试它。
我做了类似的事情:
from wsgiref.simple_server import make_server
def app_200_hello(environ,start_response):
stdout = StringIO('Hello world')
start_response("200 OK", [('Content-Type','text/plain')])
return [stdout.getvalue()]
s = make_server('localhost', 8080, app_200_hello)
class TestFunc(unittest.TestCase):
def setUp(self):
s.handle_request()
def test1(self):
r = func()
assert r, something
if __name__ == '__main__':
unittest.main()
在setUp()我的测试停止,因为s.handle_request()等待请求。我怎么能绕过那个?在另一个线程中运行s.handle_request()?或者还有另一个 溶液
编辑: 我想测试“func”函数,而不是“app_200_hello”
答案 0 :(得分:7)
如果您正在测试WSGI应用程序,我强烈建议werkzeug.test通过在没有服务器的情况下测试应用程序本身来解决这些问题:
from werkzeug.test import Client
# then in your test case
def test1(self):
client = Client(app_200_hello)
appiter, status, headers = client.open()
assert ''.join(appiter) == 'Hello World'
assert status == '200 OK'
这种方法完全消除了对WSGI服务器的需求。
当然,如果您确实想要启动服务器,则必须使用单独的线程或进程,但之后必须确保将其停止。然而,令我印象深刻的是,您唯一想要使用真实服务器进行测试的是生产集成测试,在这种情况下您的服务器将不是wsgiref,它将是一个真正的服务器,您可能不必启动 - 像这样停下来。
答案 1 :(得分:5)
使用多处理在单独的进程中启动服务器
setUp中的执行以下操作:
self.port = 8000
server = make_server('', self.port, make_my_wsgi_ap())
self.server_process = multiprocessing.Process(target=server.serve_forever)
self.server_process.start()
然后在tearDown做:
self.server_process.terminate()
self.server_process.join()
del(self.server_process)
我发现如果你没有明确地将del()放在那里,那么后续的服务器实例可能会对已经使用的端口有问题。
答案 2 :(得分:4)
您的服务器必须是一个单独的进程。
您需要使用subprocess.Popen()
如果您使用的是Python 2.6,则可以在tearDown期间终止子进程。
def setUp( self ):
self.server= subprocess.Popen( "python","myserver","etc." )
def tearDown( self ):
self.server.kill()
如果你没有使用Python 2.6,那么杀死服务器可能会令人不快。
答案 3 :(得分:2)
您还可以提供实际上不运行服务器的urlopen
的模拟版本。
假设您的原始代码位于mycode.py
,在您的测试代码中,您可以执行以下操作:
import mycode
class TestFunc(unittest.TestCase):
def setUp(self):
# patch mycode, to use mock version of urlopen
self._original_urlopen = mycode.urlopen
mycode.urlopen=self.mock_urlopen
def tearDown(self):
# unpatch urlopen
mycode.urlopen=self._original_urlopen
def mock_urlopen(self,url):
# return whatever data you need urlopen to return
def test1(self):
r = func()
assert r, something
if __name__ == '__main__':
unittest.main()
这被称为“猴子修补”,有些人不屑一顾,但是为了测试你的代码,它可以让生活变得更轻松,因为你不需要改变你原来的代码来使它变得可测试。
答案 4 :(得分:0)
我的解决方案:
URL = 'http://localhost:8085'
def func():
response = urlopen(URL)
return response.read()
import unittest
from wsgiref.simple_server import WSGIServer, WSGIRequestHandler
import threading
from urllib2 import urlopen
from cStringIO import StringIO
def app_200_hello(environ,start_response):
stdout = StringIO('Hello world')
start_response("200 OK", [('Content-Type','text/plain')])
return [stdout.getvalue()]
server = WSGIServer(('localhost', 8085), WSGIRequestHandler)
server.set_app(app_200_hello)
t = threading.Thread(target=server.serve_forever)
t.start()
class TestFunc(unittest.TestCase):
def setUp(self):
pass
def test1(self):
r = func()
self.assertEqual(r, 'Hello world')
def __del__(self):
server.shutdown()
if __name__ == '__main__':
unittest.main()
我在另一个线程中启动“server”并在TestFunc析构函数中关闭它。