使用QT4S开源框架做云api的自动化测试(二)
以下是腾讯的QTA自动化框架
QTAF(自动化基础库): https://github.com/Tencent/QTAF
QT4A( Android UI自动化): https://github.com/Tencent/QT4a
QT4i( iOS UI自动化):https://github.com/Tencent/QT4i
QT4W(支持多种平台的Web自动化):https://github.com/tencent/qt4w
QT4S(后台测试自动化框架):https://github.com/qtacore/QT4S
本文的代码来源于https://github.com/qtacore/QT4SDemoProj,
这里只是针对该源码做简要的分析,实际项目使用还得根据情况来。
demo工程的层级结构如下图所示:
要介绍的重点是hello_test.py中通过调用服务接口的方式来做自动化测试,如下图中红色框框所示
# encoding: utf-8 from testbase.testcase import TestCase from lib.hello_lib import HelloChannel, HelloService, HelloRequest from server.hello_server import HelloTcpServer import threading import sys reload(sys) sys.setdefaultencoding('utf-8') class HelloTestBase(TestCase): '''HelloTest基类 ''' def add_cleanup(self, callee, *args, **kwargs): # 添加关闭通道的方法 HelloChannel.close(),最后在post_test中调用 self.clean_ups.append((callee, args, kwargs)) def pre_test(self): self.clean_ups = [] # -------------------------------------- self.start_step('先启动一个多线程tcp服务') self.server = HelloTcpServer() threading.Thread(target=self.server.serve_forever).start() def post_test(self): # -------------------------------------- self.start_step('关闭通道链接') for clean_up in self.clean_ups: try: callee, args, kwargs = clean_up # 调用关闭通道的方法 HelloChannel.close() callee(*args, **kwargs) except: self.log_info("invoke %s with %s and %s failed" % (callee, str(args), str(kwargs))) def clean_test(self): # -------------------------------------- self.start_step('关闭tcp服务,这个可能需要2分钟左右') super(HelloTestBase, self).clean_test() self.server.shutdown()
hello_lib.py封装的是对外提供的HelloService接口服务,testcase里面可直接调用。
# -*- coding: utf-8 -*- ''' 示例lib层,这里用到的都是qt4s的框架层要求定义, 可以通过注释其中的代码,从报错的堆栈信息进入底层代码 ''' from qt4s.channel.sock import SocketChannel, RequestBase, ResponseBase from qt4s.message.definition import Field, String, Uint32 from qt4s.message.serializers.binary import BinarySerializer from qt4s.service import Service, Method class HelloResponse(ResponseBase): """hello response definition """ _struct_ = [ Field('len', Uint32), Field('seq', Uint32), Field('result', String, byte_size=0) ] _serializer_ = BinarySerializer() _length_field_ = "len" def get_sequence_id(self): return self.seq class HelloRequest(RequestBase): """hello request definition """ _struct_ = [ Field('len', Uint32), Field('seq', Uint32), Field('username', String, byte_size=0) ] _serializer_ = BinarySerializer() _length_field_ = "len" response_class = HelloResponse def get_sequence_id(self): return self.seq def pre_process(self, channel): self.seq = channel.create_seq() class HelloChannel(SocketChannel): '''hello channel ''' request_class = HelloRequest def call_method(self, method_name, req, rsp_cls, timeout): if method_name == "hello": print "Client send message {}".format(req) response = self.send(req) return response class HelloService(Service): '''对外发布的服务,供客户端访问 ''' _methods_ = [ Method("hello", HelloRequest, HelloResponse) ] if __name__ == '__main__': pass
hello_server.py里面ThreadingTCPServer是一个异步多线程的tcp服务器,用来处理客户端发起的tcp通信交互
# -*- coding: utf-8 -*- '''异步多线程的TCP服务器 ''' import socket import select import struct import traceback from SocketServer import TCPServer, ThreadingTCPServer, StreamRequestHandler from qt4s.message.serializers.binary import BinarySerializer from lib.hello_lib import HelloResponse, HelloRequest class RequestHandler(StreamRequestHandler): '''定义连接内部的处理过程 ''' def handle(self): recvbuf = "" try: while True: can_read, _, _ = select.select([self.connection, ], [], [], 1) if self.connection in can_read: buf = self.connection.recv(1000) if not buf: break recvbuf += buf buflen = len(recvbuf) if buflen >= 4: reqlen = struct.unpack("!I", recvbuf[0:4])[0] if buflen >= reqlen: body = recvbuf[:reqlen] req = HelloRequest() req.loads(body) self.on_request(req) print "receive from %s@%s: %s" % (self.client_address[0], self.client_address[1], recvbuf) except socket.error, e: if e.errno == 10054: self.connection.close() except: print ("%s" % traceback.format_exc()) print "End handling with client %s:%s" % (self.client_address[0], self.client_address[1]) def on_request(self, req): rsp = HelloResponse() rsp.result = "Hello, %s!" % req.username rsp.seq = req.seq rsp.len = 8 + len(rsp.result) rspbuf = rsp.dumps(BinarySerializer()) sent_size = 0 while sent_size < rsp.len: sent_size += self.connection.send(rspbuf[sent_size:]) class HelloTcpServer(ThreadingTCPServer): '''自定义tcp服务端 ''' def __init__(self): server_address = ('localhost', 8091) TCPServer.__init__(self, server_address, RequestHandler) if __name__ == "__main__": server = HelloTcpServer() server.serve_forever(1)