接口自动化实战之充值接口,数字商品系统接口文档

大雄 420 2022-09-05

分类专栏: 接口自动化测试

版权


接口自动化测试

专栏收录该内容

16 篇文章6 订阅

订阅专栏

接口介绍



excel测试用例



代码实操

先跑起来!

首先先通过Handler准备好三大组件的初始化(yaml_handler、excel_handler、logging_handler),接着通过excel_handler获取recharge工作表的所有数据:


test_recharge.py

import ddt

import unittest

from middleware.Handler import Handler


#初始化yaml_handler

yaml = Handler.yaml

#初始化excel_handler

excel = Handler.excel

#初始化logging_handler

logger = Handler.logger

#准备好excel测试数据

excel_data = excel.get_data("recharge")


#在需要使用到数据的类上定义ddt装饰器

@ddt.ddt

class Test_recharge(unittest.TestCase):

    # #在类中需要使用数据的方法上准备数据

    @ddt.data(*excel_data)

    def test_recharge(self,cases):

        print(cases)


if __name__ == '__main__':

    unittest.main()


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

执行结果如下:



问题1:接口依赖

业务流程上,进行充值前要先进行登录,一是为了获得登录接口返回结果的token放入headers,二是充值接口本身的请求参数中有一个member_id,它也是登录成功后接口返回的数据。因此在进行实际测试之前,需要先调用登录接口获取token及user_id。

这里我们可以在excel测试用例中对token和member_id进行参数化。那么能直接写死吗?member_id可以写死,因为只需登录一次即可获取member_id,在测试用例从开始执行到结束这个member_id都不会变;而token是无法写死的,因为token是有时限的,你如果写死了,下次再拿出来用就已经失效了,所以我们得需要一个新鲜的token。而我们在登录所获取的token_id足够我们使用到执行完所有14条测试用例,所以所有的测试用例均用同一个token_id即可。

接下来再想想,调用充值接口前调用登录接口仅仅只是充值接口的特权吗?其他接口如:提现、投资等就不需要登录吗?当然需要!所以我们需要单独把它拿出来封装成方法,然后供其他测试类调用。

那么需要在哪封装登录方法呢?common吗?自然是不行的,因为common下的都是跟业务不相关的模块,而登录已经涉及到了登录业务,自然不能放到common下,因此应该放到middleware下。


Handler.py

#省略之前的代码...

    #由于多个接口都需要依赖登录接口来登录,所以这里准备登录的接口请求

    def login(self):

        #通过request_handler请求登录接口,其中url可以从yaml中获取host再拼接上登录的url,json可以直接取yaml中的user配置项

        req = request_handler.requests_handler(

            url = self.yaml["host"] + "/member/login",

            method = "post",

            headers = {"X-Lemonban-Media-Type": "lemonban.v2 "},

            json = self.yaml["user"]

        )

        #获取返回结果中的token。由于token_info中的token_type和token的内容是分开的,所以需要拼接起来。另外需要注意取值时的层级关系

        token_type = req["data"]["token_info"]["token_type"]

        token_content = req["data"]["token_info"]["token"]

        token = " ".join([token_type, token_content])

        #获取返回结果中的用户id,因为充值接口需要用到member_id

        user_id = req["data"]["id"]

        #返回token及user_id

        return {"token":token,"user_id":user_id}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

handlers中封装完登录接口后,就可以直接在测试类中调用该方法获取token和member_id了。这里我们可以考虑通过setUpClass来获取这两个信息,一是本来调用登录接口获取这两个参数本来就是测试充值接口前的前置动作(先登录后充值);二是我们只需登录一次,获取token放入headers,获取member_id作为请求参数传给充值接口,不需要每一条excel用例都执行一遍,而setUpClass在运行所有的excel测试用例过程中只执行一次,所以应该用setUpClass。

在获取了token和member_id后,在测试方法中我们需要在调用接口前替换excel测试用例中的#member_id#和#token#


test_recharge.py

#在需要使用到数据的类上定义ddt装饰器

@ddt.ddt

class Test_recharge(unittest.TestCase):

    #前置方法,调用登录接口获得user_id和token

    @classmethod

    def setUpClass(cls) -> None:

        # 调用Handler的login方法,获取返回值中的user_id及token

        login_info = Handler.login()

        cls.member_id = login_info["user_id"]

        cls.token = login_info["token"]


    #在类中需要使用数据的方法上准备数据

    @ddt.data(*excel_data)

    def test_recharge(self,cases):

        #用变量接收excel里data字段的数据,后面请求接口传入请求参数时更方便

        data = cases["data"]

        #替换data中含有#member_id#的地方,替换成前置方法中的member_id

        if "#member_id#" in data:

            data = data.replace("#member_id#",self.member_id)

        #用变量接收excel里headers字段的数据

        headers = cases["headers"]

        #替换headers中含有#token#的地方,替换成前置方法中的token

        if "#token#" in cases["headers"]:

            headers = headers.replace("#token#",self.token)


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

执行时报了个错:


这说的是setUpClass返回的member_id是一个list类型而不是str类型,所以我们需要用str()方法把list类型转换成str类型:


#替换data中含有#member_id#的地方,替换成前置方法中的member_id

        if "#member_id#" in data:

            data = data.replace("#member_id#",str(self.member_id))

        #用变量接收excel里headers字段的数据

        headers = cases["headers"]

        #替换headers中含有#token#的地方,替换成前置方法中的token

        if "#token#" in cases["headers"]:

            headers = headers.replace("#token#",str(self.token))

1

2

3

4

5

6

7

8

问题2:多层级json的值的提取

在Handler的登录方法中,我们获取接口返回的token和user_id时是这样的:


        #获取返回结果中的token。由于token_info中的token_type和token的内容是分开的,所以需要拼接起来。另外需要注意取值时的层级关系

        token_type = req["data"]["token_info"]["token_type"]

        token_content = req["data"]["token_info"]["token"]

        token = token_type + " " + token_content

        #获取返回结果中的用户id,因为充值接口需要用到member_id

        user_id = req["data"]["id"]

1

2

3

4

5

6

由于token_type和token在第三层比较深,所以我们需要连续获取三次显得有点繁琐,这里我们可以通过引入jsonpath模块来简化多层json中获取某一层值的步骤。

接下来讲解一下jsonpath的简单用法:


data = {

    "code": 0,

    "msg": "OK",

    "data": {

        "id": 1,

        "code": 1,

        "leave_amount": 7029504.48,

        "mobile_phone": "13241562152",

        "reg_name": "SS01",

        "reg_time": "2020-10-11 16:38:11.0",

        "type": 1,

        "token_info": {

            "token_type": "Bearer",

            "expires_in": "2020-10-14 20:58:52",

            "token": "ewefwefwefwfgwg.e3f3fC1S4s2c77-Tc8Q"

        }

    },

    "copyright": "Copyright 人生有限责任公司"

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

如上面所示,data是一个3层深度的json。我们要获取第一层中的code,可以这样写,其中一个.表示子层级,即第一层级。


code = jsonpath(data,"$.code")

print(code)

1

2

打印如下:


打印出来是一个列表,而我们想获取里面的值,可以再通过索引来获取:


code = jsonpath(data,"$.code")[0]

print(code)

1

2

打印结果如下:


接下来如果我们想获取第三层级的token,可以这样写,其中两个.表示子孙层级,即包括第一层级及后面的所有层级


token = jsonpath(data,"$..token")[0]

print(token)

1

2

打印如下:


因此,如果我们想获取某一层级的参数值又懒得去数在哪个层级,直接打两个点就行了。

因此Handler中登录方法的token及user_id的获取我们可以写成下面这样:


    #获取返回结果中的token。由于token_info中的token_type和token的内容是分开的,所以需要拼接起来。另外需要注意取值时的层级关系

        token_type = jsonpath(req,"$..token_type")

        token_content = jsonpath(req,"$..token")

        token = token_type + " " + token_content

        #获取返回结果中的用户id,因为充值接口需要用到member_id

        user_id = jsonpath(req,"$..id")

1

2

3

4

5

6

问题3:Handler优化

在Handler定义了登录方法后,我们在test_recharge的测试模块中获取token和member_id时是这样的:


    #前置方法,调用登录接口获得user_id和token

    def setUpClass(cls) -> None:

        # 调用Handler的login方法,获取返回值中的user_id及token

        login_info = Handler.login()

        cls.member_id = login_info["user_id"]

        cls.token = login_info["token"]

1

2

3

4

5

6

这里我们可以再对Handler简化一下,在Handler方法中分别定义get_token和get_userId方法获取到token和user_id的值,然后直接通过Handler对象调用这两个方法获取到这两个值:


Handler.py

class Handler():

"""省略前面的代码"""

    #通过get_token方法获取login方法中返回结果中的token的值

    def get_token(self):

        user = self.login()

        return user["token"]

    # 通过get_userId方法获取login方法中返回结果中的user_id的值

    def get_userId(self):

        user = self.login()

        return user["user_id"]

1

2

3

4

5

6

7

8

9

10

接着在test_recharge测试模块中调用这两个方法获取token和member_id的值:


test_recharge

#初始化Handler对象

handler = Handler()

#在需要使用到数据的类上定义ddt装饰器

@ddt.ddt

class Test_recharge(unittest.TestCase):

    @classmethod

    #前置方法,调用登录接口获得user_id和token

    def setUpClass(cls) -> None:

        # 调用Handler的login方法,获取返回值中的user_id及token

        cls.member_id = handler.get_userId()

        cls.token = handler.get_token()

1

2

3

4

5

6

7

8

9

10

11

接下来还可以再优化一下,我们可以把方法变成一个类属性,直接通过对象.属性就可获取token和user_id的值而不需要通过对象.方法来获取。


Handler.py

    #通过get_token方法获取login方法中返回结果中的token的值

    @property

    def get_token(self):

        user = self.login()

        return user["token"]

    # 通过get_userId方法获取login方法中返回结果中的user_id的值

    @property

    def get_userId(self):

        user = self.login()

        return user["user_id"]

1

2

3

4

5

6

7

8

9

10

在test_recharge模块中我们直接通过对象.属性来获取值:


test_recharge.py

class Test_recharge(unittest.TestCase):

    @classmethod

    #前置方法,调用登录接口获得user_id和token

    def setUpClass(cls) -> None:

        # 调用Handler的login方法,获取返回值中的user_id及token

        cls.member_id = handler.get_userId

        cls.token = handler.get_token

1

2

3

4

5

6

7

而如果我们像之前那样通过对象.方法来获取值的话就会报错:


意思是Handler的get_userId返回的值是list类型的,而list类型是没有方法可调用的。


问题4:断言失败的排查

在解决了接口依赖及Handler优化的问题后,接下来我们就可以通过request_handler来请求接口获取实际结果,然后再拿实际结果来和预期结果进行断言


test_recharge.py

    @ddt.data(*excel_data)

    def test_recharge(self,cases):

        #用变量接收excel里data字段的数据,后面请求接口传入请求参数时更方便

        data = cases["data"]

        #替换data中含有#member_id#的地方,替换成前置方法中的member_id

        if "#member_id#" in data:

            data = data.replace("#member_id#",str(self.member_id))

        #用变量接收excel里headers字段的数据

        headers = cases["headers"]

        #替换headers中含有#token#的地方,替换成前置方法中的token

        if "#token#" in cases["headers"]:

            headers = headers.replace("#token#",str(self.token))

        #通过request_handler来请求接口获取实际结果

        actual_result = requests_handler(

            method = "post",

            url = yaml["host"] + cases["url"],

            json = json.loads(data),

            headers = json.loads(headers)

        )

        #用变量获取excel中的预期结果

        expected_result = json.loads(cases["expected"])

        #实际结果与预期结果进行断言

        self.assertEqual(expected_result["code"],actual_result["code"])

        self.assertEqual(expected_result["msg"],actual_result["msg"])


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

在执行时报了个错,断言失败——2!= 0:


但我们通过postman访问是返回0的:



问题5:【业务】充值成功断言

在断言接口实际返回结果与预期结果一致时,就能证明充值成功了吗?并不能,我们还得确保数据库表中的数据是正确的。在调用充值接口返回充值成功后,按理说member表中的leave_amount数字是有增加的,而增加的金额恰好就是请求参数的amount对应的值。这样一来我们可以通过下面的表达式来断言member表数据是否正确:

充值前的金额 + 充值金额(接口请求参数中的amount) = 充值后的金额(member表中的leave_amount)

这样一来就有个问题:如何获取充值前的金额?

我们可以在调用接口前查一次数据库,获取member表中的leave_amount。

这样我们就可以写出一条简单的sql查询语句:

select leave_amount from futureloan.member where ?

这里的where条件要怎么写呢?我们可以根据config.yml中的mobile_phone来查询,也可以通过请求参数中的member_id来查询。

另外又有一个问题:是不是所有的测试用例都得查询?

其实只需要对充值成功的用例进行数据库查询就行了,因为其他异常用例都因为接口的各种返回失败的情况而没有碰到数据库表那一层。那我们怎么判断哪条用例是成功的用例呢?我们可以在用例中设置一个标识字段(如sql_execute),当这个字段等于1时,则这条用例就查询数据库;否则不查询数据库。另外我们也可以把要执行的sql直接写到这个字段上,然后判断这个字段中有值,就执行对应的sql;这个字段值为空,则不执行sql。

另外,sql连接对象的初始化我们可以放到前置方法中。那是放到setUpClass还是放到setUp中呢?那么我们就要弄清楚连接对象我们是需要每一条用例都用不同的连接对象还是所有的用例都用同一个连接对象?很显然每一个用例都需要初始化一个连接对象,因为如果我们第一个测试用例执行完毕后,第二个测试用例还用上一个用例的sql连接对象,那么游标对象也还是跟上一个用例的一样,而上一个用例的游标执行完毕后它是标记在结果那一行的,并没有重置,所以再用这个游标对象是得不到想要的值的。因此我们需要每个用例都初始化一遍sql连接对象,所以应该放到setUp方法中。


test_recharge.py

import json

import ddt

import unittest

from middleware.Handler import Handler

from common.request_handler import requests_handler


#初始化Handler对象

handler = Handler()

#初始化yaml_handler

yaml = handler.yaml

#初始化excel_handler

excel = handler.excel

#初始化logging_handler

logger = handler.logger

#准备好excel测试数据

excel_data = excel.get_data("recharge")


#在需要使用到数据的类上定义ddt装饰器

@ddt.ddt

class Test_recharge(unittest.TestCase):

    @classmethod

    #前置方法,调用登录接口获得user_id和token

    def setUpClass(cls) -> None:

        # 调用Handler的login方法,获取返回值中的user_id及token

        cls.member_id = handler.get_userId

        cls.token = handler.get_token


    #前置方法,初始化sql连接对象

    def setUp(self) -> None:

        self.db = handler.mysql_class()


    #在类中需要使用数据的方法上准备数据

    @ddt.data(*excel_data)

    def test_recharge(self,cases):

        #用变量接收excel里data字段的数据,后面请求接口传入请求参数时更方便

        data = cases["data"]

        #替换data中含有#member_id#的地方,替换成前置方法中的member_id

        if "#member_id#" in data:

            data = data.replace("#member_id#",str(self.member_id))

        #用变量接收excel里headers字段的数据

        headers = cases["headers"]

        #替换headers中含有#token#的地方,替换成前置方法中的token

        if "#token#" in cases["headers"]:

            headers = headers.replace("#token#",str(self.token))

        #执行查询语句,查询调用充值接口前member表的余额为多少

        execute_01 = self.db.query("SELECT * FROM futureloan.member WHERE id={}".format(self.member_id))

        before_amount = execute_01["leave_amount"]

        #通过request_handler来请求接口获取实际结果

        actual_result = requests_handler(

            method = "post",

            url = yaml["host"] + cases["url"],

            json = json.loads(data),

            headers = json.loads(headers)

        )

        #用变量获取excel中的预期结果

        expected_result = json.loads(cases["expected"])

        #实际结果与预期结果进行断言

        self.assertEqual(expected_result["code"],actual_result["code"])

        self.assertEqual(expected_result["msg"],actual_result["msg"])

        #如果返回结果为成功

        if actual_result["code"] == 0:

            #断言member表中的leave_amount数据是否正确

            execute_02 = self.db.query("SELECT * FROM futureloan.member WHERE id={}".format(self.member_id))

            after_amount = execute_02["leave_amount"]

            self.assertTrue(before_amount + data["amount"] == after_amount)


if __name__ == '__main__':

    unittest.main()


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

在执行时又报错了,这里又报了个错:

看得出来这是sql语句的问题,异常定位在执行sql的这一句:


        execute_01 = self.db.query("SELECT * FROM futureloan.member WHERE id={}".format(self.member_id))

1

首先先从语法上来看,这句话没有语法问题,因为直接放到工具上是可以执行的:


接着我们可以尝试把id直接写死,像这样:


        execute_01 = self.db.query("SELECT * FROM futureloan.member WHERE id=1")

1

再运行一次,没报sql语句异常的错误了,所以可以断定问题出在传过来的member_id值有问题,极有可能是传过来的类型与数据库表中的类型对不上。

接着我们定位到获取member_id的前置方法上,并没有发现什么问题:


    def setUpClass(cls) -> None:

        # 调用Handler的login方法,获取返回值中的user_id及token

        cls.member_id = handler.get_userId

1

2

3

接着我们再继续定位到Handler中从登录接口返回结果中获取user_id的那一段代码:


Handler.py

        #获取返回结果中的用户id,因为充值接口需要用到member_id

        user_id = jsonpath(req,"$..id")

1

2

在这里我们发现了问题的所在,原来是user_id没有通过索引获取值,因而传到test_recharge中的值的类型为list,从而导致与member表中id的类型int对不上。

加上索引[0]之后,运行时没再报sql异常了,但又报了一个类型不匹配的异常:


异常定位到下面这段代码上:


 self.assertTrue(before_amount + data["amount"] == after_amount)

1

而异常的意思是字符串的下标必须为数字,而data[“amount”]这里我们的下标为字符串。这里我们通过具体的字段作为索引是没问题的,问题就出在data为什么是字符串类型,我们想要的data是一个字典类型。

我们接着定位到data的定义:


data = cases["data"]

1

可以看到data没有进行json.loads的转换,因此直接从excel中读取过来的数据就是字符串类型了。所以这里我们需要通过json.loads转换一下:


#省略前面的代码

json_data = json.loads(data)

#省略前面的代码

self.assertTrue(before_amount + json_data["amount"] == after_amount)

1

2

3

4

问题6:sql数据更新(提交事务)

在调试过程中我们发现,充值前金额在加上充值金额前就已经等于充值后金额了,这是不合理的,那么问题出在哪呢?


这是因为sql的事务没更新。

在初始化一个sql连接对象之后,它就会生成一个副本一样的东西,你执行的sql只是相当于在这副本上进行操作,而真正的member表是没有任何变化的。就跟git的本地仓库和远程仓库一样,你在本地仓库做了操作,远程仓库并没有任何变化,只有当你本地仓库提交时才会把数据真正地更新到远程仓库中。类比过来,初始化一个sql连接对象相当于建立一个本地仓库,在上面执行的sql增删改查操作并不会对真正的member表产生任何变化,只有当提交事务之后,本地仓库的变更才会真正同步到member表中。

因此sql_handler中得进行事务的提交:


sql_handler.py

#省略前面的代码

    def query(self,sql,is_one=True):

        #把最新的数据进行更新(提交事务)

        self.conn.commit()

        #调用游标对象的execute方法执行查询的sql

        self.cursor.execute(sql)

#省略后面的代码

1

2

3

4

5

6

7

问题7:精度控制

在第二条用例运行时报了个错:


异常定位到的位置是下面这段代码:


self.assertTrue(before_amount + json_data["amount"] == after_amount)

1

异常的意思是decimal(双精度)与float(单精度)不能相加。

关于单精度和双精度的区别见下面的引用部分:


我们提到圆周率 π 的时候,它有很多种表达方式,既可以用数学常数3.14159表示,也可以用一长串1和0的二进制长串表示。

圆周率 π 是个无理数,既小数位无限且不循环。因此,在使用圆周率进行计算时,人和计算机都必须根据精度需要将小数点后的数字四舍五入。

在小学的时候,小学生们可能只会用手算的方式计算数学题目,圆周率的数值也只能计算到小数点后两位——3.14;而高中生使用图形计算器可能会使圆周率数值排到小数点后10位,更加精确地表示圆周率。在计算机科学中,这被称为精度,它通常以二进制数字来衡量,而非小数。

对于复杂的科学模拟,开发人员长期以来一直都依靠高精度数学来研究诸如宇宙大爆炸,或是预测数百万个原子之间的相互作用。

数字位数越高,或是小数点后位数越多,意味着科学家可以在更大范围内的数值内体现两个数值的变化。借此,科学家可以对最大的星系,或是最小的粒子进行精确计算。

但是,计算精度越高,意味着所需的计算资源、数据传输和内存存储就越多。其成本也会更大,同时也会消耗更多的功率。

由于并非每个工作负载都需要高精度,因此 AI 和 HPC 研究人员可以通过混合或匹配不同级别的精度的方式进行运算,从而使效益最大化。NVIDIA Tensor Core GPU 支持多精度和混合精度技术,能够让开发者优化计算资源并加快 AI 应用程序及其推理功能的训练。

单精度、双精度和半精度浮点格式之间的区别

IEEE 浮点算术标准是用来衡量计算机上以二进制所表示数字精度的通用约定。在双精度格式中,每个数字占用64位,单精度格式占用32位,而半精度仅16位。

要了解其中工作原理,我们可以拿圆周率举例。在传统科学记数法中,圆周率表示为3.14 x100。但是计算机将这些信息以二进制形式存储为浮点,即一系列的1和0,它们代表一个数字及其对应的指数,在这种情况下圆周率则表示为1.1001001 x 21。

在单精度32位格式中,1位用于指示数字为正数还是负数。指数保留了8位,这是因为它为二进制,将2进到高位。其余23位用于表示组成该数字的数字,称为有效数字。

而在双精度下,指数保留11位,有效位数为52位,从而极大地扩展了它可以表示的数字范围和大小。半精度则是表示范围更小,其指数只有5位,有效位数只有10位。

圆周率在每个精度级别表现如下:IEEE 浮点算术标准是用来衡量计算机上以二进制所表示数字精度的通用约定。在双精度格式中,每个数字占用64位,单精度格式占用32位,而半精度仅16位。

要了解其中工作原理,我们可以拿圆周率举例。在传统科学记数法中,圆周率表示为3.14 x100。但是计算机将这些信息以二进制形式存储为浮点,即一系列的1和0,它们代表一个数字及其对应的指数,在这种情况下圆周率则表示为1.1001001 x 21。

在单精度32位格式中,1位用于指示数字为正数还是负数。指数保留了8位,这是因为它为二进制,将2进到高位。其余23位用于表示组成该数字的数字,称为有效数字。

而在双精度下,指数保留11位,有效位数为52位,从而极大地扩展了它可以表示的数字范围和大小。半精度则是表示范围更小,其指数只有5位,有效位数只有10位。

圆周率在每个精度级别表现如下:IEEE 浮点算术标准是用来衡量计算机上以二进制所表示数字精度的通用约定。在双精度格式中,每个数字占用64位,单精度格式占用32位,而半精度仅16位。

要了解其中工作原理,我们可以拿圆周率举例。在传统科学记数法中,圆周率表示为3.14 x100。但是计算机将这些信息以二进制形式存储为浮点,即一系列的1和0,它们代表一个数字及其对应的指数,在这种情况下圆周率则表示为1.1001001 x 21。

在单精度32位格式中,1位用于指示数字为正数还是负数。指数保留了8位,这是因为它为二进制,将2进到高位。其余23位用于表示组成该数字的数字,称为有效数字。

而在双精度下,指数保留11位,有效位数为52位,从而极大地扩展了它可以表示的数字范围和大小。半精度则是表示范围更小,其指数只有5位,有效位数只有10位。

圆周率在每个精度级别表现如下:

下面来看关于decimal的几个例子:


from decimal import Decimal


#双精度+整数

a = Decimal(0.3)

b = 2

print("双精度与整数的加法:0.3(双精度)+2(整数)={}".format(a+b))

#双精度+双精度

c = Decimal(0.2)

print("双精度与双精度的加法:0.3(双精度)+0.2(双精度)={}".format(a+c))

d = 0.2

#print("双精度与单精度的加法:3.1(双精度)+2.1(单精度)={}".format(a+d))

1

2

3

4

5

6

7

8

9

10

11

执行结果如下:


执行第三个例子时,执行时报错:


因此双精度与单精度是不能进行相加的,所以json_data[“amount”]应转换成双精度:

提交订单接口(按照产品编码)

请求方式:POST 参数请不要转json,就普通form格式

请求地址:http://open.kp-api.com/ms/sendFlowOrderAPI

请求参数名类型必需描述示例 e.g.
useridstring会员IDP160
mobilestring充值帐号15205201314(注 : 提卡业务请输入tika)
bizidstring商户订单ID(注 : 订单号必须唯一)只支持最长36位字符串
productidstring商品ID00101010010
notifyurlstring本条充值的状态报告推送地址http://yourreceiveurl_address
buynumstring充值数量非必填,默认为1,如果为提卡业务,数量最大为100
keystring数字签名MD5加密串(32位,小写)

详细说明:


签名规则:

MD5(userid + mobile + productid + sign),加密方式为MD5 (32位,小写)

密钥sign由充值平台方分配,请妥善保存。上线之前请告知充值平台方技术,请求服务器IP列表,通过IP 白名单加强交易安全


返回示例:

注明:下单成功时,saleprice为当前订单扣款总额,resultMsg为平台订单号

                                {"resultCode":"T00001","resultMsg":"DO150827152601707","saleprice":"20.00"}
								

充值接口(按照产品面值)

请求方式:POST 参数请不要转json,就普通form格式

请求地址:http://open.kp-api.com/ms/sendFlowOrderAPI

请求参数名类型必需描述示例 e.g.
useridstring会员IDP160
mobilestring充值帐号15205201314
bizidstring商户订单ID(注 : 订单号必须唯一)只支持最长36位字符串
typestring行业分类流量:001,话费:002,默认 002,只填写数字
pfacevaluestring商品面值10(按照元计算,例如十元)
bmanchongstring是否慢充默认为0快充,1为慢充
notifyurlstring本条充值的状态报告推送地址http://yourreceiveurl_address
buynumstring充值数量非必填,默认为1
keystring数字签名MD5加密串(32位,小写)

详细说明:


签名规则:

MD5(userid + mobile + pfacevalue + sign),加密方式为MD5 (32位,小写)

密钥sign由充值平台方分配,请妥善保存。上线之前请告知充值平台方技术,请求服务器IP列表,通过IP 白名单加强交易安全


返回示例:

注明:下单成功时,saleprice为当前订单扣款总额,resultMsg为平台订单号

	
                                {"resultCode":"T00001","resultMsg":"DO150827152601707","saleprice":"20.00"}
								

任意充值接口

请求方式:POST 参数请不要转json,就普通form格式

请求地址:http://open.kp-api.com/ms/sendFlowOrderAPI

请求参数名类型必需描述示例 e.g.
useridstring会员IDP160
mobilestring充值帐号15205201314
bizidstring商户订单ID(注 : 订单号必须唯一)只支持最长36位字符串
productidstring商品ID一元产品id,跟平台方索取
buynumstring充值数量填写充值数量
notifyurlstring本条充值的状态报告推送地址http://yourreceiveurl_address
keystring数字签名MD5加密串(32位,小写)

详细说明:


签名规则:

MD5(userid + mobile + productid + sign),加密方式为MD5 (32位,小写)

密钥sign由充值平台方分配,请妥善保存。上线之前请告知充值平台方技术,请求服务器IP列表,通过IP 白名单加强交易安全


返回示例:

注明:下单成功时,saleprice为当前订单扣款总额,resultMsg为平台订单号

                                {"resultCode":"T00001","resultMsg":"DO150827152601707","saleprice":"20.00"}
							

订单状态查询接口

请求方式:POST 参数请不要转json,就普通form格式

请求地址:http://inquery.kp-api.com/ms/queryOrderStatusAPI

注明:下单超过10分钟之后,再来查询,否则造成损失自行承担,严禁下单之后立马查询

请求参数名类型必需描述示例 e.g.
useridstring会员IDP160
orderidstring系统订单IDorderid为空时可以不加入签名计算
bizidstring商户订单IDbizid为空时可以不加入签名计算
keystring数字签名(32位,小写)MD5(userid+orderid+bizid+sign);注:orderid和bizid为空时可以不加入签名计算,但是两者必须存在一个有值

详细说明:


查询成功时,resultCode为T00002

resultMsg为订单状态:0,未充值;1:充值中;2:充值成功;3:充值失败;

resultCode不为T00002都视为查询失败,resultMsg为失败原因。

查询订单充值成功时,moredata字段为话费充值流水凭证


返回示例:

                                {"resultCode":"T00002","resultMsg":"2","moredata":"003420181003114538092850"}

订单状态通知

请求方式:POST 参数为json格式

Body参数名类型必需描述示例 e.g.
useridstring会员IDP160
orderidstring我方系统订单IDDO16121015455404245
mobilestring充值帐号15205201314
bizidstring商户订单ID
resultCodestring充值状态码T00003=充值成功;T00004=充值失败
resultMsgstring返回信息[流水号]充值成功[0034XXXX]
flownostring流水号0034XXXX
cardsInfostring卡密信息,提卡业务才会出现, 格式为json数组例如:[{'cardNo':xxxx(卡号), 'cardPwd':xxxx(卡密), 'expireTime':xxxx(过期时间) }],卡密为加密方式,解密方式请跟我们联系
refundStatusstring退款状态说明参数只在订单失败且退款成功才返回信息
keystring数字签名(32位,小写)MD5(orderid+userid + mobile+resultCode +sign);

详细说明:


合作方提供回调地址,格式"http://xxxx",当订单处理结束之后,系统会向合作方发起通知,

合作方接收到通知后返回数字1告知系统接受成功,否则系统会陆续每间隔5分钟重新推送,直到接受到数字1或连续发送5次都失败才终止!


余额查询接口

请求方式:POST 参数请不要转json,就普通form格式

请求地址:http://account.kp-api.com/ms/queryBalanceAPI

请求参数名类型必需描述示例 e.g.
useridstring会员IDP160
keystring数字签名(32位,小写)MD5(userid+sign);

返回示例:

                                {"resultCode":"T00002","resultMsg":"2999.23"}

京东直充

京东下单流程

必须先关注卡池微信公众号,才能获取用户id和秘钥

1),调用京东验证码发送接口,相同号码一分钟之内只允许调用一次,请控制流速

2),调用京东验证码回填验证接口

3),成功验证之后,调用下单接口(按照产品编码方式)

京东验证码发送接口

请求方式:POST 参数请不要转json,就普通form格式

请求地址:http://wx.wpool.cn/jdverifyCodeApi.do

请求参数名类型必需描述示例 e.g.
useridstring会员IDP160
phonenumstring发送号码15205201314
pidstring产品id00101010010
keystring数字签名(32位,小写)MD5(userid + phonenum + pid +sign);

返回示例:

                                {"result":"ok","rescode":"1","msg":"发送成功"},京东验证码只根据result判断发送结果,当result为ok时候为成功,其他都为失败

京东验证码回填验证接口

请求方式:POST 参数请不要转json,就普通form格式

请求地址:http://wx.wpool.cn/judgejdverifyCodeApi.do

请求参数名类型必需描述示例 e.g.
useridstring会员IDP160
phonenumstring发送号码15205201314
pidstring产品id00101010010
verifyCodestring京东验证码233445
keystring数字签名(32位,小写)MD5(userid + phonenum + pid + verifyCode +sign);

返回示例:

                                {"result":"ok","rescode":"1","msg":"验证成功"},京东验证码只根据result判断验证结果,当result为ok时候为成功,其他都为失败

附录

下单接口返回码

状态码描述订单状态
T00001下单成功订单已入库
T00006账户余额不足订单未入库
T00007下单失败订单未入库(详细信息)
T00008系统异常类似网络超时,返回值不能正常解析等情况,需核实处理(不可直接将订单失败,可通过查询订单接口处理)
T00009订单号已存在平台已存在该订单号,订单具体状态应查询或核实处理

订单查询接口返回码

状态码描述订单状态
T00002查询成功resultMsg=2充值成功,resultMsg=3充值失败,resultMsg=其他充值中
T00007查询失败(失败原因包括密钥不对,用户ID不对等,建议与平台核实信息)
T00010订单不存在下单请求成功并且平台返回流水号,30分钟后所查订单不存在,可失败处理

回调接口返回码

状态码描述
T00003充值成功
T00004充值失败


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:什么是股票API交易?需要注意什么风险?api数据接口 股票
下一篇:治理营销短信要见实效见长效!
相关文章

 发表评论

暂时没有评论,来抢沙发吧~