mock server —— 用于自动化测试

我们在测试某个模块的时候,该模块会依赖很多外部http server,真实搭建这样的server有两个缺点:1、部署维护成本较大,太重不适合自动化测试,2、网络异常、超时、返回部分结果等特殊情况很难测试到,这时候如果用到mock就很方便了,这里来介绍一个简单的mock server。

功能描述


模拟http服务, 同时支持get及post访问方式
提供两种set方法供用户自定义http服务response_code及response_content

接口说明

set_code_handler_func(self, func) #设置code处理方法,func接受参数为path,返回状态码,如:path:/index.jsp?galaxy=test return:200
set_content_handler_func(self, func) #设置content处理方法,func接受参数为path,返回page content,如:path:/index.html return:"hello world!"
start(self) # 启动服务
stop(self) # 停止服务

测试样例

from galaxy.mock_server import http
 
## init
server = http.MockHTTPServer(port=8000) # 默认使用8000端口
 
## set handler func
'''
模拟http服务response_code及response_content,对应提供如下两种set方法,eg:
func_code = lambda path: 504
func_content = lambda path: "hello world = " + path
 
以上func接受参数为path,当以post方式请求时path=path + “?” + data
'''
server.set_code_handler_func(func_code)
server.set_content_handler_func(func_content)
 
## start server
server.start()
 
## request code eg:
url = "http://10.250.11.57:8000/"
query = "url=http://www.taobao.com"
try:
    req = urllib2.Request(url + urllib.quote(query))
    response = urllib2.urlopen(req)
    print response.read()
    response.close()
except Exception, err:
    print str(err)
 
## stop server
server.stop()


mock_server_http.py

"""
Mock HTTP Server.

This module builds on BaseHTTPServer by implementing the standard GET and POST
requests in a fairly straightforward manner.
"""


__version__ = "1.0"

__all__ = ["MockHTTPRequestHandler", "MockHTTPServer"]

import os
import cgi
import time
import BaseHTTPServer
import SocketServer
import urllib
import shutil
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

import sys
sys.path.append("/usr/local/atest/atest-1.1.5/lib/")
import atest.log as log

class MockHTTPRequestHandler(SocketServer.ThreadingMixIn, BaseHTTPServer.BaseHTTPRequestHandler):

    server_version = "MockHTTP/" + __version__

    code_handler_func = None
    content_handler_func = None
    read_timeout = 0

    def log_message(self, format, *args):

        """override for ignore any log."""

        pass

    def do_GET(self):

        path = urllib.unquote(self.path)

        log.debug("path: %s" % path)

        self.__response(path)

    def do_POST(self):

        # Parse the form data posted
        
        form = cgi.FieldStorage(
            fp=self.rfile,
            headers=self.headers,
            environ={'REQUEST_METHOD':'POST',
                     'CONTENT_TYPE':self.headers['Content-Type'],
                     })

        data = [field + "=" + form[field].value for field in form.keys()]
        path = "%s?%s" % (self.path, "&".join(data))

        log.debug("path: %s" % path)

        self.__response(path)


    def __response(self, path):

        response_code = self.code_handler_func.im_func(path) if self.code_handler_func else 200
        response_content = self.content_handler_func.im_func(path) if self.content_handler_func else ""

        log.debug("code: %s, content: %s" % (response_code, response_content))

        f = StringIO()
        f.write(response_content)
        length = f.tell()
        f.seek(0)
        self.send_response(response_code)
        self.send_header("Content-type", "text/html")
        self.send_header("Content-Length", str(length))
        self.end_headers()
        if f:
            sleep_time = float(self.read_timeout)/1000
            log.debug("Sleep %s seconds" % sleep_time)
            time.sleep(sleep_time)
            shutil.copyfileobj(f, self.wfile)
            f.close()
        

class MockHTTPServer:

    def __init__(self, port=8000):

        self._port = port
        self._code_handler_func = None
        self._content_handler_func = None
        self._read_timeout = 0

        self._pid = 0
    
    def set_code_handler_func(self, func):

        """Code handler func, eg:
        >>>def func(path): # /index.jsp?galaxy=test
        ...    return 200
        @param func: lambda x: 200
        """

        self._code_handler_func = func

    def set_content_handler_func(self, func):

        """The same as set_code_handler_func"""

        self._content_handler_func = func

    def set_read_timeout(self, milliseconds):

        """Set read timeout"""

        self._read_timeout = milliseconds

    def _server(self, protocol="HTTP/1.0",
               HandlerClass = MockHTTPRequestHandler,
               ServerClass = BaseHTTPServer.HTTPServer):

        server_address = ('', self._port)

        HandlerClass.protocol_version = protocol
        HandlerClass.code_handler_func = self._code_handler_func
        HandlerClass.content_handler_func = self._content_handler_func
        HandlerClass.read_timeout = self._read_timeout
        HandlerClass.daemon_threads = True
    
        httpd = ServerClass(server_address, HandlerClass)

        sa = httpd.socket.getsockname()
        log.info("Serving HTTP on %s port %s ..." % sa)

        httpd.serve_forever()

    def start(self):

        log.info("Start mock http server ...")

        child = os.fork()
        if not child:
            self._server()

        self._pid = child

    def stop(self):

        log.info("Stop mock http server ...")

        if self._pid:
            os.kill(self._pid, 9)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值