LoginSignup
10

More than 3 years have passed since last update.

posted at

Pythonで接続エラーなどのテスト用のダミーWebサーバを作る

SimpleHTTPRequestHandlerを使うと、現在のディレクトリ以下のファイルを返す簡易Webサーバが作れます。
do_GETをオーバーライドすることで、ふるまいを簡単に変更できます。
do_POSTを定義すれば、POSTメソッドも模擬できます。

python2とpython3のどちらでも動く簡単な実装は以下のとおりです。

dummy_server.py
try:
    # python3
    from http.server import HTTPServer, SimpleHTTPRequestHandler
except:
    # python2
    from SimpleHTTPServer import SimpleHTTPRequestHandler
    from BaseHTTPServer import HTTPServer


class RequestHandler(SimpleHTTPRequestHandler, object):
    def print_info(self):
        self.log_message("%s %s\n%s", self.command, self.path, self.headers)

    def do_GET(self):
        self.print_info()
        super(RequestHandler, self).do_GET()

    def do_POST(self):
        self.do_GET()


httpd = HTTPServer(("", 8000), RequestHandler)
httpd.serve_forever()

ルーティング、コネクション切断、タイムアウトなど

様々なふるまいの変更を簡単にできます。

  • ルーティング的なことをするにはself.pathを書き換えることでできます
  • コネクションの切断・キャンセルを模擬するには途中でreturnするなどで
  • 応答時間を長くする(タイムアウトのテストなど)にはsleepで待つなど
dummy_server.py
    def do_GET(self):
        self.print_info()

        if self.path == "/test":
            self.path = "/dummy_server.py"
        elif self.path == "/test2":
            return
        else:
            from time import sleep
            sleep(5)

        super(RequestHandler, self).do_GET()

2回に1回エラー、はじめの2回はエラーなどの制御

リトライ実行で成功するパターンなどのテストにも使えます。

dummy_server.py
from itertools import chain, repeat
from time import sleep

try:
    # python3
    from http.server import HTTPServer, SimpleHTTPRequestHandler
except:
    # python2
    from SimpleHTTPServer import SimpleHTTPRequestHandler
    from BaseHTTPServer import HTTPServer


def close():
    return True, None


def wait(time_seconds, path=None):
    def f():
        sleep(time_seconds)
        return False, path

    return f


def page(path):
    return wait(0, path)


path_map = {
    "/test": chain([close, wait(3, "/dummy_server.py"), None, page("/dummy_server.py")]),
    "/test2": (x for seq in repeat((close, page("/dummy_server.py"))) for x in seq),
    "/dummy_server.py": chain([close, close, wait(1)], repeat(None))
}


class RequestHandler(SimpleHTTPRequestHandler, object):
    def print_info(self):
        self.log_message("%s %s\n%s", self.command, self.path, self.headers)

    def do_GET(self):
        self.print_info()

        iterator = path_map.get(self.path)
        if iterator:
            f = next(iterator, None)
            if f:
                ret, path = f()
                if ret:
                    return
                if path:
                    self.path = path

        super(RequestHandler, self).do_GET()

    def do_POST(self):
        self.do_GET()


httpd = HTTPServer(("", 8000), RequestHandler)
httpd.serve_forever()

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
10