【直播回顾】深度分享 |高建民《电动车充电云平台开发与测试实践》
Visits: 1106 次   
Release Date: 08/03/2022

iSQE对话汽车行业第三期直播活动圆满落幕,本期直播邀请到了Autonomic高建民老师进行了《电动车充电云平台开发与测试实践》主题分享,聚焦电动汽车给大家带来进行了关于电动汽车的科普宣讲。以下是高建民老师演讲的文字版内容。

 

今天我带给大家这个题目,主要是一个抛砖引玉的作用,我们来看一下在实际的软件开发和测试,这种方法论在汽车行业尤其充电这个领域的实际的应用和我自己这边的一些体会。同时我也希望带给大家带来一些关于电动车的非常浅显的知识。

我本次演讲将分为三部分,首先,从充电的角度电动车可以分为哪些;第二,让大家对充电有个基本认知; 最后从主机厂的角度来看,在实现一个云平台上线过程中,我们在开发中遇到的实际挑战以及现实和理想的差距。

我们进入正题,最近风头正旺的华为的问界、之前(比亚迪)的汉、海豚、蔚小理等等都属于新能源车。到底什么样的算新能源车,它跟电动车又有什么关系?

简单来说新能源车只是能源获取方式发生了改变。在词之前是通过燃烧汽油、柴油来获取驱动汽车前进的能量。还有另外一个领域是氢燃料电池。

今天我们主要是讲以电池为驱动力的电动车。在前几年,路上大部分是油车,同时少量的绿牌开始出现,其中有大部分叫混动。

比如,荣威,它的混动的混指的是,动力来源方式除了传统的油之外,车上还有一块小电池,用混合的方式提供动力,有串联、并联。

大家比较容易理解的一种方式是,如果从动力的损耗和能源的利用率来讲,车在起步的时候,从静止到加速至60公里这段时间能量消耗是最大的。如果是油车,它的能量的利用率很低,损耗很大,如果换成电的话,效率很高,因为电直接会通到驱动车轮的电机上,所以加速度就会很高。

一般的电车说有的是542,可能百米加速5秒钟,有的时候三点几秒,就是因为它这个电机直接去驱动到车轮中间的损耗路径会比较短一点。

最近两三年,纯电车比较多,比如蔚来的ES8。

纯电车Battery Electric Vehicles;插电混动Plugin Hybrid Electrical Vehicle。还有其他的方式,比如增程式,它有个发动机,也有电池,但发动机不会去驱动轮子,发动机就是给电池充电。理想好像有一款车就属于增程式。

插电混动的特点:

  1. 插电混动和纯电里面都有电池,可以很容易看到插电混动的电池的容量要小很多,因为它里面有发动机占空间。
  2. 针对相对比较老的一些车型的插电混动,大家去实体店去看车的时候,尤其混动的,可以看一下后备箱。如果后备箱的空间比较小,车辆的研发平台最初设计不是针对电动车而是针对汽油车,所以整个布局都是按照发动机、变速箱为主。如果看到后备箱空间比较合理,可能是重新为新能源车设计的一种平台。

纯电车的特点:

电动车基本上是从0开始做了一个车辆研发平台,它的电池基本上是平铺在车辆底盘,可能是前轮和后轮之间。它电池本身很重,而且又靠近地面,因为车重心很低、很稳,转向的时候,不太会容易发生侧翻。当然坏处就是如果撞到的话,因为锂电池的安全性到目前还没有一个彻底的解决方案,最近台湾特斯拉车撞击起火,根本原因还是电池受到剧烈撞击产生了爆燃。

给电动车电池充电跟我们手机充电差不多。在车里面有一个OBC(车载充电机),车辆充电的快和慢取决于很多地方,比如充电桩,进入车的设备,它能够提供的功率是多少,车本身的车载充电机给电池充电的时候,功率又是多少,这相当于就是木桶效应,看谁慢了,看瓶颈在哪里。

 

最后从续航的角度来讲,现在城市通勤,开纯电车的用户有“里程焦虑”,但目前已经得到了极大的缓解,纯电车的续航已经接近1000公里跟油车区别不大。不过在天气比较冷的时候,它的续航力会下降比较厉害。整体而言,在续航的可靠性上,可能还是混动的稍微好一点。

 

以前车没油了,开去加油站,把加油箱一插,等着就行。现在多了一个充电的这个东西,它叫充电桩,充电的场站,叫充电站,按照它的地理位置分公共充电站和家用充电桩,比如在大型商超的地下停车库、停车位上;在停车场的停车位上,更多的是,像上图左侧,这种叫做交流的充电桩;右侧图,像专业的大型设备,叫直流的充电桩,因为它在充电的时候发热相当厉害,所以里面有一个大功率的风扇用于降温,噪音很大;还有一种是在买车的时候,4s店会让你选,给你装一个充电桩,这种目前为止绝大部分也都是交流的,以后的趋势会逐渐转成小功率直流的,因为在充电速度上能够提供保障。

一辆车提供哪几种充电方式,比如交流和直流,一般纯电的新能源车,它两种都有,交流的叫慢充,直流的叫快充。混动的一般找不到快充。这里会有些数学的东西,大家可以算一算。我们交流电,充电桩是左图黑色的,它的插口是右图中靠右边的,大家去数一下是有7个孔。交流充电,它的电压是220伏,我们家里一个电流的大小一般是10安培,比如有些空调设备是16安培。到了交流充电桩的时候,它是32安培,这一乘,差不多刚好是7千瓦。对于车来说,充电桩输入功率是70千瓦,当然技术也在进步,可能后面会有瓦数更高,比如11千瓦的交流充电桩。大家就会算可以算一下,比如小鹏P7,电池是80千瓦,算一下慢充差不多要11个小时,我相信自己有电动车的网友算的应该比我还熟。

直流相对而言会复杂一点,它的一个普遍特征是基本上都能保证在一个小时之内冲到80%。这里可以留意一下,现在很多主机厂设计直流的充电的时候,在开始的时候基本上是全功率输出、全功率充电,可让你快速充电。一般到了80%之后,功率急速下降,基本上进入一个交流充电的模式,这是防止电池过热,对电池的寿命进行保护。

所以要完全充满其实一个小时不够,有些主机厂随车的一些APP,可以看到实时曲线变化。现在外面公共充电常见比较多的是特来电,它好像是跟高铁还是国家电网有点关系的,所以它目前在充电供应商里面基本是排第一,它的设备、它的充电质量,包括它的软件体验是最好的。

还有比较常见的是国家电网,这个是国字头的,它的覆盖是最大的。比如高速公路上,服务区里面,据我的观察只有国家电网,其他都没有。

除此之外,还有星星充电,小桔充电,充电队长,现在有很多APP,你可以去地图上去找哪里有充电站,比如说高德,百度,主机厂给你的这些,甚至他们这些充电商本身也提供了对应的APP,它功率很复杂,一般最低电压会是在200伏,电流会比较高一点,那么这么一来的话,我就最小的功率可以到60千瓦。

还有一种新的技术叫超充,可能750伏或者800伏,对应的电流也很大,体验就尽可能靠近给车加油的体验,比如给车加油,20升的油箱可能两三分钟三五分钟就够了。如果有一天充电能达到这个程度,充电的体验感就比较好,不需要每次充电等很久。

还有一种家用设备,像一个插头插到家用插头上,另外一头有个适配器可以插到车上。这种功率是非常小,可能比7千瓦还要低。一般在应急的时候,或者目的地没有固定充电桩的时候使用,它充的慢但是对电池而言比较安全。

 

我们再来看一下软件部分,接下来还是围绕着公共充电的使用场景。

大家的选择入口很多,微信小程序里面有很多软件开发商提供的小程序来给车充电,也有原生的APP,支付宝里面也有小程序可以给车充电,甚至地图的应用里面都有对应的功能。

大家日常能看到在用户端,我们去公共充电的时候,如果是租新能源车,我们第一步要做什么?在我列在了上图右边,可以给你们参考。

因为公共充电场所,在对应的充电桩上都会有一个二维码,有的是在机器上贴的一张纸,有的是在屏幕上。记得一定要先要把枪插好,然后拿手机扫二维码,这个时候手机会给到云端的后台发个什么东西,充电桩其实有一个链接,我们国家也有相应的一些标准,叫互联互通的一个标准。它把充电桩唯一识别的一个ID发到云平台。如果你用的手机APP是车厂,像大众、宝马,还有国产的各种品牌,数据会发到车企的云平台,能够知道是用户发起了充电以及充电桩的ID是多少。

云平台收到充电请求之后,因为用了APP,也可以知道用户信息,去看用户在这里充电了,是否他的车在这里也上传了信息,因为对车来说检测到有充电桩插进来,这时候如果有一个事件上报到车辆的车联网云端,就能够知道用户这时候要充电。如果我要给你免费充电的话,这时候就可以应用到这个场景,把优惠券都给匹配好。接下来要去按开始充电的按钮,有些做的好的平台不用点开始,直接就启动了。这就是从扫码到启动的过程。

在点下启动之后它发生了什么事情?其实在主机厂,这些充电桩都是独立的运营商,像我刚才提到特来电、星星充电等品牌。比如你扫特来电, CPU我们就叫充电运营商,发到他的后台去。如果是主机厂,不可能每一家都去接,有16个二十几个品牌的充电提供商,都接二十几次。对主机厂,这不是它的业务重点。他可能就会选择充电的聚合商这一类,也有的可能想把这个东西放在自己手里,可以做到一致的用户体验等等,这是要自己去权衡的。

然后发生了什么?把你充电桩的ID发给到车的后台,充电桩充电,这个云平台收到之后,刚才里面我没有提的是它在充电之前它会有一个鉴权的过程,一个认证的设备认证和用户交互的一个过程,对用户来说它是不可知的,有时候点启动实际上就是授权,现在还有新的一种技术叫即插即充,把枪插上去,什么都不用管,就可以开始充电了,这种是更加复杂了,我们以后有机会再讲。

CPU在收到充电桩的ID后,因为充电桩上都会有4G芯片,它里面有sim卡,它有对应的MCU硬件上的控制单元去控制充电桩工作,而且会有个长连接连到云平台,而且通信是双向的,可以从云端给它下发指令,告诉充电桩启动充电,这时候通过它上面4G的卡,指定进入充电桩内部,最后开始闭合充电电路,这样就会有车能源进入车上,这是充电启动的过程。

 

启动之后会发生什么事情?物联网在日常随处可见,充电桩本身就是一个物联网的设备。在充电开始之后,隔30秒或者隔一分钟或者更短,往云端去发数据,比如我在充电,现在的电压是多少,现在的电流是多少,或者有的算出了现在功率是多少,到了云端之后,再由充电桩一路返回,最后展示到用户的终端设备上。

这样在手机上能看到充电的曲线、一些类似仪表盘一样的这种图形界面来反馈充电充了多少。这里有个小细节,如果你是用的主机厂APP,不管是交流还是直流充电,都能看到车充到了78%、 82%,或者50%,因为车是有信息过来,能够关联在一起。如果用的是第三方,直流的还好,交流的无从得知电池实际电量是多少,我们叫SOC,你没法知道,所以靠猜。有的APP是,需要用户提供车型和电池含量,从而进行计算,比如总的电量是这么多,然后现在交流充电计时功率能算出,从而推算出充电进度。

为什么我说直流没什么问题,它一共有9个孔,中间最大的2个就是直流的一个电流输入的地方,还有最下面的这里边有两个小孔,这个有都有相应的国标的,他这两个是拿来进行数据传输了,把你车上的电池的一些基本的SOC,现在充到了百分之多少,这些信息云端可以收到。这就是为什么能够在手机上去看到现在实际充电充了多少。

充电什么时候停止?比如你去逛商场,插了直流桩,充满了它就停了,这个是默认设置,不会给你充爆的。充电供应商、主机厂、第三方都有对应的安全保护。还有一个小冷知识的,如果去公共充电的场所,如果你的车发生了什么意外,所有的充电桩上面都有一个红颜色的按钮,叫紧急停止,可以手拍下去强制让它停止充电。因为有时候在地下车库的信号并没有那么好,充电没办法停止,不停止充电枪无法拔出,因为在充电枪和车充电插口有一个电子锁,紧急停止之后锁会开,尤其是直流的,而且直流的很重,拔起来比较费力。这个是一种自然停止,还有做的功能好的叫定时定量。还有你自己在APP上去点,这些都是关于怎么去充电,最后记得把枪拔掉,直流桩上面有一个往下按的,按下去要用力拔。这是整个充电场景的流程。

我们现在再来聚焦的图里面蓝颜色的部分,一般我们要做这样一个平台,最核心的一些功能在这个图里面给大家标了出来。在蓝色之外,比如 OEM云平台里面的话,还有车联网系统和其他的系统,在车联网、用户数据、用户中心这些都是现成的功能。对我来说他们是上游系统,我可能要去做用户信息和车辆信息进行的一个关联,还有用户的手机号码去做关联,做人车绑定。牵扯到充电,就会有一个对充电桩设备控制的模块。最终这个牵扯到付钱,一般都是后付,充完走人,最后来付钱。就会有相应的一个订单、支付模块。有时候搞活动,会有类似优惠券模块。

如果最后要做用户的行为分析,就需要一些统计数据,这些统计数据怎么来,比如说我要去回放我的充电曲线,我们之前接到过一些客服电话,比如这辆车充电充到一半,就停下来了以及电充不进去了发现车上没数据上来,充电曲线就上去了一下就跳下来,然后变成一个静止状态,一般要么是没插好,要么是车出问题了,这些数据就是要靠充电终端上报的数据把它给存起来,这是我们主要的一些功能。

那么再比如我们要去看报表、车这些统计。比如今天有多少辆车在充电,因为充电桩都是在一些物理的场所,对应的是一些地理的位置信息,在哪个商场充电的人会更多一点?是不是可以跟充电厂家进行去合作?或者说做一些促销广告,比如打上某个车企的 logo,或者做一个包装,吸引用户到那里去充电等等,这些分析就会很重要。当量到了一定的规模,就是我们现在常见的大数据、推荐这一类的技术。

 

这些都是理论的东西,现在回到现实里。以我参与领导带团队开发的这一个架构为例子来给大家分享一些东西。

我们做的是车企的充电云平台,手机APP只有一小部分功能,主要工作在后端。我们当时做的这个东西,基本上分三个阶段,在刚刚开始的时候只有一个单体,所有的代码都在一起,大家只是为了把这个功能能做出来,能让东西跑出来。

我们也有业务部门,人家觉得这个项目没有做砸,有东西证明出来。有时候在产品管理,我们就管它叫MVP。而且你在部署了之后,它只是一个单体,不能拿来给终端用户去用的,但是内部验证它是非常好用的。为什么开始做单体?它原因会很多,比如当时开始的时候,只有我一个能写代码,其他人都要靠我招进来。

那些是外派的过来的同事,大家的背景、技术水平都会参差不齐,一开始就要做一个高并发的系统,这个显然不现实,单体在开始的时候是比较好的一个选择。除此之外,在充电行业,国家有个标准,叫互联互通,比较熟悉软件领域的同学可能知道这里面就会牵扯到对称加密,在这个地方就是车企云平台和后面供应商平台里面的所有数据每一次都是要去加密的。哪怕是查询充电桩的信息,那都是发数据说明,数据要加密,对方收到之后要解密,对方回给你的一样要解密。所以这一块技术也是比较复杂的,花费了不少时间。

在我们团队主要开发的岗位完全到岗,大家把业务了解差不多之后,因为国家标准充电流程是怎么样,大家都是照着这个来做的,业务就开始稳定了。这一部分是充电的标准有关的,我把它抽出来单独放在一个模块里面。市场部的同事说将来要去搞促销,只要是这个用户在充电都可以给他发优惠券,还是用户的这辆车再充电我才会给他优惠券。这些是跟订单、促销优惠有关,得把它都按照功能分开来。

这个地方我们仍然是一个单体,因为团队还是比较小,人员还没有到岗,我们没有去拆,最后我们把这些拆成了很多模块,大概有七八个模块,按照这个领域模型,比如用户订单是一个模块,用户信息本身是一个模块,车辆信息又是一个模块,物联网设备的控制又是一块,比如前面提到的统计。那么按照什么方式来做的?

当时我们做了一些思考和研究,后来引入了叫做DDD(Domain-Driven Design)的方法体系,就是领域驱动模型。最终的状态是软件开发人员和市场部的同事,他们可以用同一个语言去沟通。比如电卡,下个月给每个用户发20度电,他知道这个功能该怎么实现,中间不需要其任何人做中间意思上和需求上的翻译,这是我们达到的一个目的。

所以在这个领域驱动模型设计里面,它有一个最关键的就是语言一定要统一,所有的语言是体现了这个业务本身的,不是做CRUD的,我们是做领域的。在这里如果扩展开来的话,就是最后建模是怎么去建?熟悉云端开发,还有Java开发的可能就知道了它基本上有三层,最下面数据库,上面有ORM一层,最下面repository一层,再上面服务DAO这些东西,但是我们一般中间这里面还有个Entity,一般我们怎么去做的呢?比如我有个订单,我就可能有order这么一个类,可能一个order number,然后也有很多的get、set这类东西。

这个业务逻辑怎么办?比如要停止这个订单,没支付就不给他充电。这种在往上一层 Service里,比如订单支付优惠券如果是交叉在一起,这个逻辑放哪呢?这个时候边界就开始变得模糊,会有混乱,如果再加上需求一直在变化的话,管理其实是相当复杂的,我们这边是怎么做呢?

前面提到的比如订单这个里面,只有订单号等这些,这种模型在DDD里面,我们把它叫做贫血模型,因为你的东西很少。我们真的要去做的,要去推荐的一个最佳实践是什么?把它变成充血模型,意思就是说:一个订单除了订单的这些基本属性之外,它有什么行为?

比如充电订单它可以去停止,就会有停止的方法对外暴露。停止内部是做什么,比如说把这个订单状态变了,要发事件出去,让其他的模块来订阅事件,比如要有支付或者统计这些事件出去,所有这些行为都是在我这一个类里面。不在我上面的service,上面的service最多就是起一个聚合的作用,和其他的模块之间怎么沟通。再往上还有一层应用层,因为充电订单是针对实现真正业务逻辑的地方,当通过微服务拆开跟其他系统进行交互的时候,不可能把这里面这么复杂东西发给别人,所以要做一个转换,这个就是我们用到一个叫做DTO的Date Transfer Object。这个我们主要用的是DDD的,那么在跟第三方的系统去交流的时候,在DDD里面还加了一层叫防腐层,在防腐层里面才用到了DTO,这样所有的业务逻辑对外都是封闭的,是自包含的。比如现在做的是RESTful API,我只要把DTO改改就可以了,你的数据模型就可以变。如果有一天要 grpc进来,里面的业务层完全不用动,只要再另外去建一些DTO就可以了。两个接口的数据模型、属性、命名都可以完全不一样,内部的核心业务层完全不受变化,就是DDD给我们带来的好处。

DDD说着很简单,但做的时候还是有很多灵魂拷问的思考,比如订单和充电桩控制到底是一个什么样的关系?到底要是分拆成两个模块,还是放在一个模块的不同的 model里,这个会需要拉着我们的产品经理,市场部的业务合作伙伴来看到底真正要解决的什么的问题,这里面让大家把这个需求了解的更加透彻。还有尤其牵扯到后面的一些支付优惠,这些其实更加的复杂,因为它有很多条件,这些条件在哪里去设,而且我们还有集成了外部的很多系统。

到了第三阶段,其实是上线之后的,在上线之前开始的时候车很少,因为在车真正量产和用户开始买的话中间有一个时间差,所以先保证能够准时上线,所以准时上线用的是第二个阶段DDD的,我们上线之后开始用户比较少,我们才会有时间静下心来去拆微服务。

或许是机缘巧合,或许是我们做了正确的事情。在拆微服务的时候,在业务这一块几乎没有踩到什么坑,因为我们就很自然而然的把原来这些DDD里面的一个模块一个模块演变成了一个一个单元的微服务,就会变成一个分布式的系统。在微服务,我们还是用了Spring全家桶:Spring Boot,再加上Spring Cloud,自然而然就会顺很多。里面的配置管理,我们用了Spring Cloud Config Server,后面的配置信息我们是放在Github里面,服务注册的话是用Eureka。后面的有些细节可以在互动环节我们再来看。

 

最后来看一下在这个过程当中实际遇到的一些问题。这里面的挑战在前面其实有提到了,开始的时候后端其实只有我一个人,因为这个平台里面大概有差不多60%的代码是我写的,重构了若干遍。一个稳定的系统重构是必须要去投入,重构不是说你写的代码不好,你的认知在提高,你对业务的认知也在变化,需求也在变化,如果把这个东西比如一条蛇的话,重构就像它是在蜕皮,在重生。

大家水平不齐,DDD大家都不熟,我给大家做一个DDD的培训,我们也没有专门的测试员,而且在最开始的时候我们想得很好,因为高层说直接引入最先进的结对编程,后来只我一个人,我们就来搞测试驱动开发了。我一个人的时候可以这样试,因为我对业务的了解足够多,我先写好test case。然后比如到了服务这一层你没有实现就test case,这时候跑这个测试的时候,所有测试是失败的,然后加一个功能,失败的测试个数少一个,失败的测试个数降到0的时候,就意味着你的功能全部实现了,这个是测试驱动。

在我当时的项目里面的话,这套其实没有成功的去用下来,主要还是因为这里有个大的背景,就是说测试驱动开发、结对编程对于软件工程师的要求还是比较高,大家的水平都是能够独当一面的,这样子做这种才会比较顺一点。

还有的挑战刚才也有提到了,第三方系统去集成的时候,这里面就有很多跟安全方面相关的,比如这个地方跟第三方平台的要有加密技术,然后它是对称加密,大家都有一套初始化向量,有密钥还有对方的密钥,到底加密的时候用我的还是用对方的,这每个理解不一样,因为国家标准只说推荐、应当怎么样。每个人的理解都不太一样。而且云平台一定是跟外部的系统去集成,比如说我们跟微软云的集成,就要用到微软云的Azure AD,那又是一个认证的体系。还有比如API的权限等等,这些就会变得很复杂。

而且前面图里面大家也看到了,整个充电流程当中,有时候包括我们自己测试发现启动充电怎么这么慢,因为点下去将近30秒40秒才会反馈。这是正常的,因为确实它的链路很长,而且要得到反馈是要充电桩往上去上报数据的,要等。而且它互联互通的标准都是异步的。

对用户端来说,如果按照异步的话,对刚开始的团队来说异步实现会难很多,如果做成同步的话,只能去等在这里去轮询,所以你会感觉会时间比较长。还有的问题是调试会比较困难,比如说到底购买电费的时候,那是谁的问题?是 CPO的问题?比如说充电提供商-特来电他们的问题?他们充电桩的问题?他们有云平台的问题?还是说车企OEM的云平台问题,还是说手机APP网络的问题,整个调试是相当的困难。面对这么多的困难怎么去做?我们这里有个特点,这个图里面大家能看到,云端也有,设备也有,而且设备不止一种,就变得复杂很多。

 

 

从测试的角度,怎么去解决这样的问题?我们再来看这张图,仍然是手机APP,只是没有自己研发原生的APP,反而做了一专门拿来内部测试用的小程序,里面就简单的几个按钮。小程序在开发模式的时候可以打日志,这个就很方便,所以开始的时候我们用自研的小程序代替了还在开发中的用户app。

 

中间云端没什么太大变化,比如我在办公室里上哪去找充电桩?我们有替代的方案,比如我们拿电吹风,它是一个工作负载,充电也是一个负载,电吹风它是个有效载荷,可惜只能用交流充电。

我们在淘宝上买到了一个设备,可以插交流充电桩,把它转换成普通的插座,把东西插上去就连到外面的充电桩上,这仍然是对硬件或者是对一些物理的东西有一些强依赖。我们怎么解决的呢,先把这个留到后面。

 

从测试的角度来看,因为我们的后端全部是用Java做的,都是 JUnit,所以默认这一类的全部用了单元测试,就是所有的assert都把它做好。这是我们当时设的第一个目标。

第二个目标就是单元测试的覆盖率,因为人力和时间限制,可能覆盖率非常高,要求很低。在业务逻辑这些类里面,覆盖率class level,类这一个层次的,至少60%,这是开始设置比较容易达到的目标,这样大家才有动力,否则整天就在修这些测试的问题了。然后我们还做了集成测试包括系统内部和第三方的集成。

除此之外的话,因为APP和我的云是天生的前后端分离的方式,我们就引入了 Api测试,我们通过Jmeter和Python我们写了一堆的测试脚本,每次在跑的时候,会端到端把整个充电场景关键路径上全部会覆盖一遍,这些通过之后那才会进行下一步。还有手机端的自动化测试,这是针对 UI界面的,最终还有一个端到端的,那是全链路了,比如从充电扫码开始,一直到我把钱付完,这里面还牵扯到钱款的问题,这是我们所有牵扯到的测试方面。

我们是怎么做的这些测试呢?

一、因为前面也提到了,我们对这些物理的硬件设备,比如充电桩、车,这其实都是有要求的,没有这些配合,我们很多东西是做不出来,这也是很强的一个依赖。

二,在软件层面,模块之间,服务之间也有依赖,我们用替换的方式。简单来说就是模拟或者用mock,详细大家可以看上图PPT的表格,当时我们在集成测试和单元测试没有分的特别清楚,比如用 Junit或 Sprint Boot,我们没有加Spring Boot Test(没有使用 @SpringBootTest 注解),我用了Mockito,这是很简单的,它很快,几十毫秒这个类就测过去,如果加Spring Boot Test(带上 @SpringBootTest 注解)会把那些依赖的东西都会注入进来,整个就会慢很多了。在引入Spring Boot Test的同时也把mockito也加进来,比如我现在只测订单和订单状态改变的部分,对充电控制和支付不想去测怎么办?我把它模拟出来就可以了。这个mockito大家自己可以去网上去了解,它有对应的支持的方式。

对于API,在代码里面用了 restassured,测 controller,这样的话就跟着代码一起一直可以去测。再到后期,引入了专职的测试人员。测试人员更加擅长的是Python和Jmeter这些测试测试工具和技术,我们就换成Python的API测试的一个小套件。

还有一个问题,当把内部的这些解决之后,比如后面有了开发环境和自己的测试环境,跟外部集成怎么办?第三方的平台能不能模拟掉?开始认为不行,因为每次充电,第三方有他自己的系统要去测试,最后就是怎么做?因为他们也跟我们有一样的痛点,就是测试的时候得找个充电桩,最起码有个负载。

因为我们的供应商的话,它是对充电技术这一块更加专业。既然大家有共同的特点,所以我们就提议开发一个模拟的充电的环境,它可以模拟一个充电桩,他们是买了这个设备,放在他们的办公室里面,只是信号到充电桩上了,没有真正的充电行为发生。

这样的话整个充电过程就快很多,比如在启动充电的时候,这次测的不是性能,不是它的响应时间,测的是功能,这边通过云平台发起充电,那边很快就可以给到回复,就看链路通和不通,对双方非常有益。

后来我们把开发环境和他们的模拟环境直接对接起来。我们在ci的时候,代码check in进去之后会做一个完整的build,这些中间会有一些测试,测试过之后会更新开发环境,在开发环境更新之前,会跑这些真实的环境和真实的这些测试,如果这些过了之后,才把新的build刷到我们的开发环境里面。

后来我们的测试环境是对接的他们的预发布环境。其实对我们理解是半模拟的,它有一部分是模拟的,比如充电桩、其他东西它都是真实的,甚至充电要付费,当然我们掏的是真金白银,给到了我们的供应商,最后他们会给我们退款.为了就是尽可能模拟用户端真实的体验。

还有像扫二维码,充电桩二维码怎么做?一开始我们看到充电桩就拍张图片收集起来,最后收集了一些静态数据以及尽可能是有一些差异性,或者一些异常情况的充电桩测试数据。拿来做我们的输入,来测试扫码过程,因为扫码体验就是像微信一样,对准一个二维码,立马就想看到这个结果,(用户)不想看了半天,没反应,还以为手机有问题。最终整个平台级别的功能测试,针对场景的话,模拟东西就比较多。

自带的模拟设备,前面图片里面大家也有看到,还有我们研发的小程序,最后直到我们去租市面上能够租到的这些新能源车,不管是混动的,还是纯电的,开过去把各个品牌的充电桩都去试一遍,确实发现很多问题,而且每一个品牌的车的充电行为不完全一样,最后真正的开着要量产的新车去测,那才是代表最终用户开的车辆的充电体验。

 

在过程当中用了哪些测试,怎么去用这些测试,最后这些是我想给到大家的一些分享,可能是班门弄斧,可能对大家能能起到一些启发作用。

我认为在业务场景相对比较复杂的时候,如果你是一个纯粹的做 infrastructure这一层的不需要。如果是针对c端的这一类的话,业务产品比较复杂,强烈建议大家去使用的DDD(domain driven design)的技术,用到什么程度、什么级别取决于你自己。

当时我们无意间用到的比较好的地方,叫event sourcing,用户端在充电的时候,充电桩生成的最后一个数据核心,其实是订单,每当订单的状态有一次变化,就会有一个事件产生,就会有一条新的记录插入到数据库里去,并不是直接去改订单这张表里面这一行的状态,是下面这个事件我先持久化,再去同步我的订单,这样的好处,我们最后出来一个内部用的网页,看这个订单,因为有时候会有些投诉会有些这个问题过来,你看这个订单到底出现了什么问题,为什么明明我这个快充1个小时就充完了,他结果4个小时还没充完?这时候之前的事件我们可以做一个回放,如果不用DDD的话,还是比较难以做到,因为它是一个成熟的体系。

第二部分,测试覆盖一开始的时候,测试确实很重要,不是方法级别做95%,这个是给自己挖巨坑,不能本末倒置,可以设置一个适当的目标,比如能够得着的地方,60%刚好及格,而且保证我的一些关键业务都能覆盖到。其实在开始已经可以解决的绝大部分的问题,开始的时候也有并没有那么稳定。

然后软件硬件级别的模拟是相当的重要,这里我列给大家了,比如Mockito 、spock、spring boot test。还有像硬件上面,有些车,在这个车机里面,充电桩插上,坐在车里面等充电,中控屏上有个按钮,从那里去给他充电,这时要有个车机在那里,怎么去模拟这个东西?如果这个车机恰好它是一个安卓系统,可以去模拟,如果说我还想硬件的信号去做配合,它不一定能解决,而且车企都会有一个专门的模拟硬件,一个硬件可以模拟整辆车的各种信号等等。

最后,因为我们做的是一个分布式的系统,它是所有的交互微服务之间的交互,我们是通过 Restful API,所以这时候的API就会非常重要。这里推荐一个东西叫API first design。我们当时做了一个方法在开发新功能之前,(针对用户的新功能)比如有个订单的页面,流转后,签到我后端的 API了,那么怎么做呢?我先开发我的API文档,比如说swagger OpenAPI,把这个文档开发出来,前端后端拉在一起。因为我们的产品会给我们一个类似于UI的 Use Case的图,use case、API放一边,大家来评估,这个 API能不能实现我们要的功能,如果这些没问题了,分头拿着这个API去开发,这样前端对后端的依赖我就把它就给解决掉了。

最后我们专职的QA也是照着这个去写他的测试用例,出问题很容易就发现,所以 API测试在这种非单体的分布式这里面,还是非常重要的。

如果想把整个流程自动化,持续集成非常重要。如果用 github,gitlab这些都自带一些持续集成的功能,有自己的actions、有自己的 Pipeline,你提一个Pull Request可以直接自动触发一些简单的单元测试。强烈建议大家用这些,当然Jenkins不在话下。最后两个是跟上线之后的事情有关,比如开发的时候大家开得很爽,DDD这么好,如果真的出了问题,你两眼一抹黑。比如微服务里面有10个服务,1个用户场景里面链路里面有牵扯到6个,怎么能快速去定位是在哪一个微服务上面出错挂掉了,这就牵扯到链路调用追踪的问题。如果再跟你的上下游系统再去集成,这些更长的链路里面到底是谁的问题?这是我讲的最后一个点,图中已经列给大家。比较推荐的是OpenTelemetry这个是基于标准去做,它是一个规范,照着规范去开发,将来后端的软件怎么变,你的代码实现部分不用变。

除此之外,应用的日志也相当重要,在写日志的时候,不能从头到尾全部是debug或者是trace,更加不能都是error,异常也不能直接把它吞了,否则上线之后,就知道它的坑在哪了。这些基本上就是我想今天带给大家的分享和个人体验,我这边分享就到这里了。

 

演讲嘉宾

高建民,目前就职于Autonomic,担任资深产品经理,在软件开发领域有丰富经验,先后以不同角色参与软件开发生命周期中的各种活动。现在主要专注汽车行业软件应用在云上的各种架构、设计和开发。

资料获取

演讲PPT分享:点击:链接 获取演讲PPT(百度网盘提取码:iSQE)

演讲视频回放:想了解更多精彩内容,欢迎点击:链接 查看查看直播回放

返回