一、微服务概述
本质是一种架构模式,是SOA(面向服务型架构)的一种变体,每个服务围绕具体的业务进行构建,可以独立部署;每个服务运行于独立的进程中,服务间用Rest API进行通讯。
单体架构
优点
1、团队组织结构简单,易于集中管理
2、开发进度一致,避免重复开发
3、所有功能都在本地,没有远程调用开销
缺点
效率低、维护困难、不够灵活、稳定性不好、扩展性不够
微服务优势与缺点
优势
1、解决单体式架构缺点
2、部署、回滚更加便捷
3、每个服务可以独立扩容
4、每个服务可以用适合的技术栈实现
5、可以用插件的形式更新系统,不必每次更新重新部署整个系统
6、对于业务数据可以用数据接口方式,方便后续发展业务数据的管理和迁移
缺点
1.每个子系统有独立的团队,增加团队交流成本,系统内部通信开销增加
2.分布式架构的自动化部署、项目测试、项目管理复杂度大大提高
3.代码重复,同业务代码无法封装成工具类进行调用
二、微服务测试
对测试影响:
1、每个微服务承担一定职责,尽可能小,又要达到一定规模
2、微服务间通过Rest API进行连接
3、每种服务不一定有界面,不一定能够从UI进行完整测试
4、微服务通常可以划分为更小的模块,可以考虑从不同的模块入手进行测试
微服务测试面临的挑战:
1、服务/模块之间复杂的依赖关系
2、不同的服务可能在不同的环境下运行
3、涉及多个服务的UI端到端测试容易出错
4、测试结果可能取决于网络稳定性
5、故障的分析复杂度随着服务增加而提高
6、与不同的开发团队之间的交流成本
微服务测试原则:
1、自动化
2、层次化(单元-接口-UI,粒度:细-粗,速度:快-慢)
3、可视化(测试结果可视化)
微服务主要测试方法:
1、单元测试(验证服务内部业务、通信)
2、集成测试(验证服务外部数据、通信)
3、组件测试(微服务是否起到预期作用)
4、契约测试(组件外部,关联的组件间契约的正确性)
5、端到端测试(整个系统的功能是否满足,UI)
6、探索测试
三、微服务契约测试(链路追踪)
什么是契约测试:
基于契约,对消费者和生产者间的协作验证。本质是验证生产者提供的内容是否满足消费者的期望
契约概念:
请求请求头、url、请求的动作、参数响应生产者服务对于前面请求的应答,包含响应的状态码、内容、错误描述等元数据对消费者和生产者之间的协作过程的描述,如:生产者/消费者名称、上下文及场景描述
契约类型:
1、消费者驱动的契约类型(CDC)
2、生产者驱动的契约类型
流程:
1、对消费者的业务逻辑进行验证时,先对其期望的响应做模拟提供者(Mock);并将请求(消费者)-响应(基于模拟提供者)的协作过程,记录为契约;
2、通过契约,对提供者进行回放,保证提供者所提供的内容满足消费者的期望。
契约测试价值:
验证生产者响应,但是保障的是消费者服务
契约测试设计:
工具:Pact
1、在生产者所面向的消费者项目代码中编写测试,期望响应设置于模拟的服务生产者上。
2、在测试运行时,模拟的服务将返回所期望的响应。请求和所期望的响应将会被写入到一个”pact”文件中。
3、pact文件中的请求随后在生产者上进行回放,并检查实际响应以确保其与所期望响应相匹配。——pact-verifier –provider-base-url=http://localhost:8000 –pact-url=consumer01-provider.json
''' pact-python契约测试示例'''import atexitimport unittestimport requestsfrom pact import Consumer,Provider# 定义一个契约(pact),明确消费者与生产者,明确契约文件的存放路径pact_demo=Consumer('consumer02').has_pact_with(Provider('provider'),pact_dir='./pacts')# 服务启动pact_demo.start_service()#服务的注册atexit.register(pact_demo.stop_service)class PactDemo(unittest.TestCase): # 定义契约的内容 def test_pact(self): # 定义预期的响应结果 expected = { 'name': 'xxxx', 'age': 18 } #定义契约的实际内容 (pact_demo .given('test service') .upon_receiving('for pact') .with_request('get','/provider') #向生产者发送请求时,需要注意请求方法、路径、参数、头部信息等 .will_respond_with(status=200,body={'first':'xx','second':'yy'})) #生产者在被请求之后返回的响应的结果。可以自己定义内容的 # 基于requests库向pact发送请求,验证契约生成的结果是否正确 ,请求的实际上是pact自带的mock服务,端口默认是1234 with pact_demo: resp = requests.get('http://localhost:1234/provider').json() print(resp) # 断言校验,判断预期结果是否与pact的结果相符合 self.assertEqual(expected,resp)if __name__ == '__main__': pd = PactDemo() pd.test_pact()