2009-03-11 2 views
3

私はこの1つのようないくつかの機能を持っています。使用wsgiref.simple_serverは

私はこのようなものでした:セットアップ時


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() 

は((s.handle_requestので)私のテストは停止)要求を待ちます。どのように私はそれを回避することができますか?別のスレッドでs.handle_request()を実行しますか?別の ソリューションがありますか?

編集:私はあなたがWSGIアプリケーションをテストしている場合ではない「app_200_hello」

答えて

7

が、私は強く、サーバなしでアプリケーション自体をテストすることによって、これらの問題を回避してwerkzeug.testをお勧めすることができ、「FUNC」の機能を、テストしたい :

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ではなく、実際に起動する必要のないサーバーになりますこのようにしてください。

+0

ありがとうございました。それは私が欲しいもののように見えます。しかし、werkzeugは大きすぎます。クライアントクラスhttp://dev.pocoo.org/projects/werkzeug/browser/werkzeug/test.py#L551はwerkzeugパッケージの他の部分から独立していますか? –

+0

いいえ、それは独立していませんが、開発のための大きな依存関係ではありません。実際それは小さいです。 –

+0

ああ。私は絡み合った。私はapp_200_helloをテストしたくありません。私は "func"を試してみたい –

3

サーバーは別のプロセスである必要があります。

あなたは、Python 2.6を使用している場合、あなたはその後、ティアダウン時のサブプロセスを殺すことができるsubprocess.Popen()

でそれを開始することをお勧めします。

def setUp(self): 
    self.server= subprocess.Popen("python","myserver","etc.") 
def tearDown(self): 
    self.server.kill() 

Python 2.6を使用していない場合は、サーバーを強制終了すると不快になることがあります。

+0

私は良い考えだとは思わない。私の場合、各テストの後、システムがPythonを開始/停止することは非常に難しいでしょう。そして、私はいくつかの複雑なwsgiアプリケーションをテスト用に記述したくありません。私は、多くのシンプルなwsgiアプリケーションを多くの状況で記述したいと考えています。 –

+0

tearDownはWSGIサーバーを停止させるため、Pythonは正常に終了します。システムがPythonを停止するのは非常に簡単です。 –

+0

wsgiref.simple_serverは、別のプロセスとして開始する必要があります。 –

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() 

 

私はTestFuncデストラクタで別のスレッドやシャットダウンそれで "サーバー" を起動。

+0

あなたはありません各テストの後にサーバーが悪い状態になることを心配し、テストに影響を及ぼしますか?あなたはどのようにクッキーをテストしますか?これを行う必要がある場合は、プロセスを使用して、要求ごとに処理することを検討してください。 –

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

使用マルチプロセッシングような何か:ティアダウンで、その後

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() 

の操作を行います。

self.server_process.terminate() 
self.server_process.join() 
del(self.server_process) 

場合という私を見つけました明示的にdel()をそこに置かないと、後続のサーバーインスタンスがすでに使用されているポートに問題がある可能性があります。

+0

これはIMOを実行する最良の方法です。 – vangheem