在单元测试中使用wsgiref.simple_server

时间:2009-03-11 13:22:10

标签: python unit-testing wsgiref

我有一些像这样的功能:


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”

5 个答案:

答案 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析构函数中关闭它。