测试技能提升-接口测试11-dubbo接口测试
接口测试
案例练习
传智健康管理系统,是一款应用于健康管理机构的业务系统。采用可视化界面管理,提高健康管理师工作效
率,加强与患者间的互动
前端:http://mobile-health-test.itheima.net
后端:http://manager-health-test.itheima.net
Dubbo接口测试
RPC
远程过程调用(Remote Procedure Call):像调用本地方法一样,调用远程方法。
常见的RPC框架有 Dubbo、Thrift、grpc
Dubbo
Dubbo是一款高性能、轻量级、基于Java的开源RPC框架(最早由阿里开源,2018年贡献给了Apache组织)
Dubbo接口的作用:远程调用 java 写的方法。 需要传参、获取返回值。
查阅API文档
从中获取哪些信息?
服务名
方法名
参数类型、返回值类型
java中 方法定义语法结构:
返回值类型 方法名(数据类型 形参1,数据类型 形参2,…)
void:代表没有返回值、没有参数。
Telnet工具远程调用
启用telnet
telnet远程连接服务
连接语法:连接语法:telnet IP 端口号
telnet调用服务接口
命令格式:invoke 服务名.方法名(实参)
示例:invoke MemberService.findByTelephone(“13020210001”)
python借助dubbo远程调用
Dubboclient,封装了 telnetlib 库。 telnetlib 是 python 内置模块,可实现远程调用 Dubbo 接口
安装dubboclient
pip install dubboclient
查验:
在 pip 中:pip list 或 pip show dubboclient
在 pycharm中:file - settings - 项目名下的 python 解释器列表
实现步骤:
1. 导包 from dubboclient import DubboClient
2. 创建 DubboClient类实例,指定 IP 和 port
3. 使用 实例调用 invoke() 方法。 传入 :服务名、方法名、实参(方法使用)。获取响应结果
4. 打印响应结果
会员服务(入门)
案例1
根据手机号,查询会员信息(传递 普通参数)
dubbo> ls -l MemberService
com.itheima.pojo.Member findByTelephone(java.lang.String)
接口定义:Member findByTelephone(String telephone)
参数:
字符串格式手机号。唯一
返回值:
成功:返回 会员的信息内容。string类型 包裹的 字典数据。
失败:返回 null。string类型
实现代码:
# 1. 导包 from dubboclient import DubboClient
from dubboclient import DubboClient
# 2. 创建 DubboClient类实例,指定 IP 和 port
dubboclt = DubboClient("211.103.136.244", 6502)
# 3. 使用 实例调用 invoke() 方法。 传入 :服务名、方法名、实参(方法使用)。获取响应结果
resp = dubboclt.invoke("MemberService", "findByTelephone", "13020210001")
# 4. 打印响应结果
print("响应结果 =", resp)
print("type(resp) =", type(resp))
添加会员(传递 对象参数)
dubbo> ls -l MemberService
void add(com.itheima.pojo.Member)
接口定义:void add(Member member)
参数:
1. 自定义类 做 参数,根据接口文档,组织 “字典” 格式数据传参
2. 给字典增加 键k:”class“ ,值v:指明 类 对应的 完整 包名和类名
如:"class”:"com.itheima.pojo.Member"
ls -l MemberService 可以查看完整包名和类名。
区分自定义类: 包名不以“java.”开头。一般采用:com.公司名.项目名.类名
返回值:
成功:返回 null
失败:返回 Failed
实现代码:
# 1. 导包
from dubboclient import DubboClient
# 2. 创建 dubboclient 实例
dubboclt = DubboClient("211.103.136.244", 6502)
# 准备 add 方法,所需要的数据
info = {"id": 911, "name": "杜甫", "phoneNumber": "13048379884"}
# 如果 class 已经存在,覆盖原有class值; 如果不存在 class,新增一组 元素到 字典中。
info["class"] = "com.itheima.pojo.Member"
# 3. 调用 invoke 传 服务名、方法名、实参。得响应结果
resp = dubboclt.invoke("MemberService", "add", info)
# 4. 打印
print("响应结果 =", resp)
print("type(resp) =", type(resp))
根据日期统计会员数(传递 字符串列表)
dubbo> ls -l MemberService
java.util.List findMemberCountByMonths(java.util.List)
接口定义:List<Integer> findMemberCountByMonths(List<String> months)
参数:
1. 字符串列表。用字符串表示年、月,用“.”衔接
如:["2021.3", "2021.9"]
返回值:
成功:返回列表,对应参数设置的月份的会员数。
失败:Failed
实现代码
# 1. 导包
from dubboclient import DubboClient
# 2. 创建 dubboclient 实例
dubboclt = DubboClient("211.103.136.244", 6502)
# 3. 用实例 调用invoke() ,传入 服务名、方法名、实参。 得响应结果
months = ["2021-7"]
resp = dubboclt.invoke("MemberService", "findMemberCountByMonths", months)
# 4. 查看响应结果
print("响应结果 =", resp)
print("type(resp) =", type(resp))
其他模块
添加预约设置
dubbo> ls -l OrderSettingService
void add(java.util.List)
接口定义:void add(List<OrderSetting> list)
参数:
1. 字典列表。字典有 orderDate 和 number 两个字段。
如:[{"orderDate":"2021-09-20 16:45:12","number":20}]
2. 日期格式:"2021-09-20 16:45:12",必须包含时分秒,否则失败。
返回值:
成功:null
失败:Failed
实现代码
# 1. 导包
from dubboclient import DubboClient
# 2. 创建 dubboclient 实例
dubboclt = DubboClient("211.103.136.244", 6502)
# 准备 add 方法,所需要的数据
info = [{"orderDate": "2021-05-18 18:89:02", "number": 346}]
# 3. 调用 invoke 传 服务名、方法名、实参。得响应结果
resp = dubboclt.invoke("OrderSettingService", "add", info)
# 4. 打印
print("响应结果 =", resp)
print("type(resp) =", type(resp))
按月统计预约设置信息
dubbo> ls -l OrderSettingService
java.util.List getOrderSettingByMonth(java.lang.String)
接口定义:List getOrderSettingByMonth(String date)
参数:
字符串,如:"2021-09"
返回值:
成功:返回字符串类型数据,字符串内容为列表
失败:Failed
# 1. 导包
from dubboclient import DubboClient
# 2. 创建 dubboclient 实例
dubboclt = DubboClient("211.103.136.244", 6502)
# 月份
moths = "2021.02"
# 3. 调用 invoke 传 服务名、方法名、实参。得响应结果
resp = dubboclt.invoke("OrderSettingService", "getOrderSettingByMonth", moths)
# 4. 打印
print("响应结果 =", resp)
print("type(resp) =", type(resp))
根据日期修改预约设置数量
dubbo> ls -l OrderSettingService
void editNumberByDate(com.itheima.pojo.OrderSetting)
接口定义:void editNumberByDate(OrderSetting orderSetting)
参数:
1. 自定义类,用 字典 根据接口文档组织数据
2. 需要使用 class 指定参数对象的类型
如:{"orderDate":"2021-10-13 21:04:33","number":15,
"class":"com.itheima.pojo.OrderSetting"}
3. 日期格式为:"2021-10-13 21:04:33",必须包含时分秒
返回值:
成功:null
失败:Failed
# 1. 导包
from dubboclient import DubboClient
# 2. 创建 dubboclient 实例
dubboclt = DubboClient("211.103.136.244", 6502)
# 日期 和 设置数据
date = {"orderDate": "2021-06-15 16:99:77", "number": 120}
date["class"] = "com.itheima.pojo.OrderSetting"
# 3. 调用 invoke 传 服务名、方法名、实参。得响应结果
resp = dubboclt.invoke("OrderSettingService", "editNumberByDate", date)
# 4. 打印
print("响应结果 =", resp)
print("type(resp) =", type(resp))
根据用户名查询用户信息
dubbo> ls -l UserService
com.itheima.pojo.User findByUsername(java.lang.String)
接口定义:User findByUsername(String username)
参数:字符串类型,如:'admin'
返回值:
用户存在:返回用户信息
用户不存在:返回 null
# 1. 导包
from dubboclient import DubboClient
# 2. 创建 dubboclient 实例
dubboclt = DubboClient("211.103.136.244", 6502)
# 管理用户名
name = "admin"
# 3. 调用 invoke 传 服务名、方法名、实参。得响应结果
resp = dubboclt.invoke("UserService", "findByUsername", name)
# 4. 打印
print("响应结果 =", resp)
print("type(resp) =", type(resp))
现有问题:
远程调用的 7个 dubbo接口 存在的问题:
- 代码有 大量冗余
- 测试接口时,除了要给 测试数据之外,还需要 指定 服务名、方法名
- 传参时,除了要考虑测试数据外,还要分析是否要添加 class 字段 及 对应数据。
- 返回的数据类型统一为 string(不具体)
封装目标
5. 只关心:测试数据、响应结果
6. 返回的结果 分别为 不同的 具体类型。
Dubbo接口自动化测试框架
核心模块
基础服务对象封装
from dubboclient import DubboClient
class BaseService(object):
def __init__(self):
self.dubbo_client = DubboClient("211.103.136.244", 6502)
服务对象封装
会员服务封装
"""
类名:MemberService,继承于 BaseService
实例属性:
服务名称:service_name,赋值为 'MemberService'
实例方法:
def __init__(self):
# 先调父类__init__(),再添加实例属性 service_name
def find_by_telephone(self, telephone):
# 功能:根据手机号查询会员信息
# :param telephone: 手机号
# :return: 1. 会员存在,返回会员信息 2. 会员不存在,返回None
def find_member_count_by_months(self, data_list):
# 功能:根据日期统计会员数
# :param date_list: 日期列表,格式如:["2021.7"]
# :return: 返回列表,列表元素为对应月份的会员数,如:[10]
def add(self, info): 添加会员
# 功能:添加会员
# :param info: 会员信息的字典格式数据,参考接口文档填入字段数据,手机号需要唯一
# 如:{"fileNumber":"D0001", "name":"李白", "phoneNumber":"13020210002"}
# :return: 添加成功返回True, 添加失败返回False
验证结果:
# 1. 实例化对象
# 2. 通过实例对象调用实例方法
# 2.1 根据手机号查询会员信息
# 2.2 根据日期统计会员数
# 2.3 添加会员
"""
import json
from day02.base_service import BaseService
# 将 会员服务 封装成 会员服务类
class MemberService(BaseService):
def __init__(self):
super().__init__() # 调用父类 init 方法
self.service_name = "MemberService"
def find_by_telephone(self, tel):
resp = self.dubbo_client.invoke(self.service_name, "findByTelephone", tel)
if resp == "null":
return None
else:
# 作用:将 string类型的 数据,还原回成 字典 或 列表 数据。
return json.loads(resp)
def find_member_count_by_months(self, months):
resp = self.dubbo_client.invoke(self.service_name, "findMemberCountByMonths", months)
# 作用:将 string类型的 数据,还原回成 字典 或 列表 数据。
return json.loads(resp)
def add(self, info):
"""
:param info: 代表 用户 传入的 测试数据,没有 class 元素
:return:
"""
# 如果 class 已经存在,覆盖原有class值; 如果不存在 class,新增一组 元素到 字典中。
info["class"] = "com.itheima.pojo.Member"
# 3. 调用 invoke 传 服务名、方法名、实参。得响应结果
resp = self.dubbo_client.invoke(self.service_name, "add", info)
if resp == "null":
return True
else:
return False
if __name__ == '__main__':
ms = MemberService()
resp = ms.find_by_telephone("13020210001")
print("响应结果 =", resp)
print("type(resp) =", type(resp))
print("=" * 66)
months = ["2021-6"]
ms = MemberService()
resp = ms.find_member_count_by_months(months)
print("响应结果 =", resp)
print("type(resp) =", type(resp))
print("&" * 66)
# 准备 add 方法,所需要的数据
info = {"id": 911, "name": "杜甫", "phoneNumber": "13048379041"}
ms = MemberService()
resp = ms.add(info)
print("响应结果 =", resp)
print("type(resp) =", type(resp))
预约设置服务封装
"""
类名:OrderSettingService,继承于 BaseService
实例属性:
服务名称:service_name,赋值为 'OrderSettingService'
实例方法:
def __init__(self):
# 先调父类__init__(),再添加实例属性 service_name
def add(self, date_list):
# 功能:添加预约设置
# :param date_list:
# 1. 日期列表,如:[{"orderDate":"2021-09-20 16:45:12","number":20}]
# 2. 日期格式为:"2021-09-20 16:45:12",必须包括时分秒
# :return: 设置成功返回True, 设置失败返回False
def get_order_setting_by_month(self, date):
# 功能:按月统计预约设置信息
# :param date: 日期,如:"2021-08"
# :return: 列表,指定月份的预约信息
def edit_number_by_date(self, info): 根据日期修改预约设置数量
# 功能:根据日期修改预约设置数量
# :param info:
# 1. 预约设置的字典格式数据,参考接口文档填入字段数据
# 2. 如:{"orderDate":"2021-09-19 17:45:12","number":15}
# 3. 日期格式为:"2021-09-19 17:45:12",必须包括时分秒
# 4. 添加 "class":"com.itheima.pojo.OrderSetting"
# :return: 修改成功返回 True, 修改失败返回 False
验证结果:
# 1. 实例化对象
# 2. 通过实例对象调用实例方法
# 2.1 添加预约设置
# 2.2 按月统计预约设置信息
# 2.3 根据日期修改预约设置数量
"""
import json
from day02.base_service import BaseService
# 封装 预约设置服务类
class OrderSettingService(BaseService):
def __init__(self):
super().__init__()
self.service_name = "OrderSettingService"
def add(self, date_list):
# 功能:添加预约设置
# :param date_list:
# 1. 日期列表,如:[{"orderDate":"2021-09-20 16:45:12","number":20}]
# 2. 日期格式为:"2021-09-20 16:45:12",必须包括时分秒
# :return: 设置成功返回 True, 设置失败返回 False
resp = self.dubbo_client.invoke(self.service_name, "add", date_list)
if resp == "Failed":
return False
else:
return True
def get_order_setting_by_month(self, month):
# 功能:按月统计预约设置信息
# :param months: 日期,如:"2021-08"
# :return: 列表,指定月份的预约信息
resp = self.dubbo_client.invoke(self.service_name, "getOrderSettingByMonth", month)
if resp == "Failed":
return None
else:
return json.loads(resp)
def edit_number_by_date(self, date):
# 功能:根据日期修改预约设置数量
# :param info:
# 1. 预约设置的字典格式数据,参考接口文档填入字段数据
# 2. 如:{"orderDate":"2021-09-19 17:45:12","number":15}
# 3. 日期格式为:"2021-09-19 17:45:12",必须包括时分秒
# 4. 添加 "class":"com.itheima.pojo.OrderSetting"
# :return: 修改成功返回 True, 修改失败返回 False
date["class"] = "com.itheima.pojo.OrderSetting"
# 3. 调用 invoke 传 服务名、方法名、实参。得响应结果
resp = self.dubbo_client.invoke(self.service_name, "editNumberByDate", date)
if resp == "Failed":
return False
else:
return True
if __name__ == '__main__':
oss = OrderSettingService()
# 准备 add 方法,所需要的数据
info = [{"orderDate": "2021-05-18", "number": 346}]
resp = oss.add(info)
print("响应结果 =", resp)
print("type(resp) =", type(resp))
print("============== 按月统计预约设置信息 ===========")
oss = OrderSettingService()
# 月份
months = "2021.02"
resp = oss.get_order_setting_by_month(months)
print("响应结果 =", resp)
print("type(resp) =", type(resp))
print("============== 根据日期修改预约设置数量 ===========")
# 日期 和 设置数据
date = {"orderDate": "2021-06-15 16:99:77", "number": 120}
oss = OrderSettingService()
resp = oss.edit_number_by_date(date)
print("响应结果 =", resp)
print("type(resp) =", type(resp))
用户服务封装
"""
类名:UserService,继承于BaseService
实例属性:
服务名称:service_name,赋值为'UserService'
实例方法:
def __init__(self):
# 先调父类__init__(),再添加实例属性 service_name
def find_by_username(self, username):
# 功能:根据用户名查询用户信息
# :param username: 用户名
# :return: 1. 如果用户存在,返回用户信息 2. 如果不存在,返回 None
验证结果:
# 1. 实例化对象
# 2. 通过实例对象调用实例方法
"""
import json
from day02.base_service import BaseService
# 封装 用户服务类
class UserService(BaseService):
def __init__(self):
super().__init__()
def find_by_user_name(self, name):
# 3. 调用 invoke 传 服务名、方法名、实参。得响应结果
resp = self.dubbo_client.invoke("UserService", "findByUsername", name)
if resp == "null":
return None
else:
return json.loads(resp)
if __name__ == '__main__':
# 管理员用户名
name = "李白"
us = UserService()
resp = us.find_by_user_name(name)
print("响应结果 =", resp)
print("type(resp) =", type(resp))
测试用例对象封装
import unittest
# 借助 unittest 框架,封装测试类,从 TestCase 继承
from day02.py02_会员服务类封装设计 import MemberService
class TestFindByTelephone(unittest.TestCase):
ms = None
@classmethod
def setUpClass(cls) -> None:
# 创建MemberService实例
cls.ms = MemberService()
def test01_tel_exists(self):
tel = "13020210001"
resp = self.ms.find_by_telephone(tel)
print("手机号存在 =", resp)
self.assertEqual("13020210001", resp.get("phoneNumber"))
def test02_tel_not_exists(self):
tel = "13020218973"
resp = self.ms.find_by_telephone(tel)
print("手机号不存在 =", resp)
self.assertEqual(None, resp)
def test03_tel_has_special_char(self):
tel = "1302021abc#"
resp = self.ms.find_by_telephone(tel)
print("手机号含有字母特殊字符 =", resp)
self.assertEqual(None, resp)
参数化
- 导包 from parameterized import parameterized
- 在 通用测试方法上一行,@parameterized.expand()
- 给 expand() 传入 [(),(),()] 类型的数据。
- 修改 通用测试方法,添加形参,个数、顺序与 () 数据一致。
- 在 通用测试方法 使用形参
import unittest
from day02.py02_会员服务类封装设计 import MemberService
from parameterized import parameterized
# 借助 unittest 框架,封装测试类,从 TestCase 继承
class TestMemberService(unittest.TestCase):
ms = None
@classmethod
def setUpClass(cls) -> None:
cls.ms = MemberService() # 创建MemberService实例
# 通用测试方法(参数化)
@parameterized.expand([("13020210001", "13020210001"),
("13020218973", None),
("1302021abc#", None)])
def test_findByTelephone(self, tel, except_data):
# print("tel =", tel, "except_data =", except_data)
resp = self.ms.find_by_telephone(tel)
if resp is None:
self.assertEqual(None, resp)
else:
self.assertEqual(except_data, resp.get("phoneNumber"))
@parameterized.expand([(["2021.5"], [3]),
(["2017.4"], [0])])
def test_findMemberCountByMonths(self, month, except_data):
resp = self.ms.find_member_count_by_months(month)
print("============ resp =============", resp)
self.assertEqual(except_data, resp)
# def test01_tel_exists(self):
# tel = "13020210001"
# resp = self.ms.find_by_telephone(tel)
# print("手机号存在 =", resp)
#
# self.assertEqual("13020210001", resp.get("phoneNumber"))
#
# def test02_tel_not_exists(self):
# tel = "13020218973"
# resp = self.ms.find_by_telephone(tel)
# print("手机号不存在 =", resp)
#
# self.assertEqual(None, resp)
#
# def test03_tel_has_special_char(self):
# tel = "1302021abc#"
# resp = self.ms.find_by_telephone(tel)
# print("手机号含有字母特殊字符 =", resp)
#
# self.assertEqual(None, resp)
接口自动化框架封装
测试报告
# 导包
import unittest
from htmltestreport import HTMLTestReport
# 创建 suite 实例
from scripts.test_member_service import TestMemberService
suite = unittest.TestSuite()
# 添加测试用例
suite.addTest(unittest.makeSuite(TestMemberService))
# 创建 HTMLTestReport 类对象
runner = HTMLTestReport("./report/传智健康测试报告.html", description="描述", title="标题")
# 调用 run() 传入 suite
runner.run(suite)
更多推荐
所有评论(0)