关于SCF序列化char类型测试的思路演进

SCF序列化测试的流程图

cx-序列化测试思路图.png

根据这个流程图来设计char类型的测试case,不能通过,原因如下

  • go端原生不支持char字符型,目前go端是用int16来封装char类型
  • 在json中不支持char类型,json中只支持 字符串、布尔值、数字(整数和浮点数)、null、对象、数组
  • 如果在json中以单个字符的字符串表示char,java可正常解析,go端不能正常解析,go端不能将字符串直接解析至int16中
  • 如果在json中以数字或数字字符串表示char, java端解析错误,不能将大于一个字符的数字解析至char类型中

基于以上的问题,想到了一个解决问题的思路,在json文件中只支持一个端的正常解析,因为java的char类型是原生支持的,所以就在json文件中用单个字符的字符串表示char,在go端手动设计,也支持同样的数据和处理逻辑。实现代码如下:

  json文件中数据
  { "GoMethodName":"BasicTypeChar","GoInputParam":{"BasicType":{"charParam":"0"}},"JavaReturnData":{"BasicType":{"charParam":"1"}},
    "JavaMethodName":"testchar","JavaTypes":"char","ElemKey":"charParam","JavaMapKey":"testchar3","PtrFlag":false},
  { "GoMethodName":"BasicTypeChar","GoInputParam":{"BasicType":{"charParam":"c"}},"JavaReturnData":{"BasicType":{"charParam":"d"}},
    "JavaMethodName":"testchar","JavaTypes":"char","ElemKey":"charParam","JavaMapKey":"testchar2","PtrFlag":false},
java端实现代码
public char testchar(char param,String javaMapKey) throws Exception {
        log.error("\n testchar-DataParamObj-javaMapKey:  "+javaMapKey);
        log.error("\n testchar-DataParamObj-this-module:  "+this.module);
        DataParam DataParamObj = DataDrive.getDataParamFromMap(this.module,javaMapKey);
        //如果验证通过,就返回对象中设定好的数据
        if (param == DataParamObj.getGoInputParam().getBasicType().getCharParam()) {
            return DataParamObj.getJavaReturnData().getBasicType().getCharParam();
        }
        return param;
}
//go端char的实现思路
func (st *basicTypeTest) BasicTypeCharOld(s DataJsonStruct) {
    charMap := make(map[byte]byte)
    javaKeyMap := make(map[byte]string)

    charMap['0'] = '1'
    javaKeyMap['0'] = "testchar3"
    charMap['c'] = 'd'
    javaKeyMap['c'] = "testchar2"

    for goinput, javareturn := range charMap {
        sdata := codec.Character(goinput)
    
        fmt.Printf("\n -----JavaMethodName----------%v", s.JavaMethodName)
        fmt.Printf("\n -------JavaTypes----------%v", s.JavaTypes)
        fmt.Printf("\n ------tdat----------%v\n", sdat)

        res, err := BasicTypeService.proxy.Invoke(s.JavaMethodName, s.JavaTypes+";String", sdata, javaKeyMap[goinput])

        if err != nil {
            fmt.Printf("[BasicTypeChar] Function  failed, err:%s", err)
        }
        fmt.Printf("\n[BasicTypeChar] Function  success,Java return data ---:%v\n", res)

        checkdat := codec.Character(javareturn)

        compareRes := InterfaceComparator(res, codec.Character(javareturn))
        fmt.Printf("\n [BasicTypeChar] Java return data compare The check data result is  ---:%v\n", compareRes)
        if compareRes == false {
            panic(fmt.Sprintf("[BasicTypeChar] serialize failed,Java return the result is not the expected result : javareturn=%v, checkdat=%v\n", res, checkdat))
        }
    }
}

此种实现方式的弊端:
将实现逻辑和数据驱动耦合在一起了,下次对于扩展char类型的测试数据,还需要修改代码,跟序列化测试最初的测试思路违背了。为了解决这个问题,还是需要将数据驱动和具体的代码实现逻辑分开。

具体的思考过程:
一开始思考,用string来表示两端的数据,在go端将string转成char传到java端,java端接收到数据之后,再将json中的String数据转成char进行对比。由此,上网查询,go和java端的转换实现。
后来在思考的过程中,发现用int类型应该会更简单,int类型在go和java端的转换都比较容易。需要注意的点就是,设置的数据范围不能超过char的最大值65535。

具体的实现代码如下:
json数据

 { "GoMethodName":"BasicTypeChar","GoInputParam":{"BasicType":{"intParam":-32765}},"JavaReturnData":{"BasicType":{"intParam":32788}},
   "JavaMethodName":"testchar","JavaTypes":"char","ElemKey":"intParam","JavaMapKey":"testchar","PtrFlag":false}

java服务端代码

public char testchar(char param,String javaMapKey) throws Exception {
        log.error("\n testchar-DataParamObj-javaMapKey:  "+javaMapKey);
        log.error("\n testchar-DataParamObj-this-module:  "+this.module);
        log.error("\n testchar-DataParamObj-param:  "+param);
        
        DataParam DataParamObj = DataDrive.getDataParamFromMap(this.module,javaMapKey);
        //临时check的数据
        int tmpCheckData =  DataParamObj.getGoInputParam().getBasicType().getIntParam();
        log.error("\n testchar-DataParamObj-tmpCheckData:  "+tmpCheckData);
        //将int数据转成char
        char chekData = (char)tmpCheckData;
        log.error("\n testchar-DataParamObj-chekData:  "+chekData);
        if( param == chekData) {
            //临时返回的数据
            int tmpReturnData = DataParamObj.getJavaReturnData().getBasicType().getIntParam();
            log.error("\n testchar-DataParamObj-tmpReturnData:  "+tmpReturnData);
            char returnData =  (char) tmpReturnData;
            log.error("\n testchar-DataParamObj-returnData:  "+returnData);
            return returnData;
        }
        return param;
}

Go端实现代码

func (st *basicTypeTest) BasicTypeChar(s DataJsonStruct){
    //此处json中用int类型的原因是java端的char是无符号16bit,可支持的码是0-65535,如果用short达不到这个范围,java端的short最大数也是32767
    //用int16进行强转的原因是Character底层设计是int16
    tmpInputParam  := int16(s.GoInputParam.BasicType.IntParam)
    //将int数据转换成char
    tdat := codec.Character(tmpInputParam)
    res := sendRequestToServer(basicTypeModule,s.GoMethodName,s.JavaMethodName,s.JavaTypes,tdat,s.JavaMapKey)
    if(res  != false ){
        tmpReturnParam := int16(s.JavaReturnData.BasicType.IntParam)
        checkdat := codec.Character(tmpReturnParam)
        checkReturnData(basicTypeModule,res,checkdat,s.GoMethodName)
    }
}

这里需要注意的是:
go端是有符号的int16,取值范围是-32768~32767, java端的char取值范围是0~65535,在go端传负数到java端,会进行有符号到无符号的转换,同样,在java端返回大于32767的数据,到go端会自动解析成负数。因为在序列化的底层,是通过二进制来计算返回值的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容