整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

数据科学家易犯的十大编码错误,你中招了吗?

数据科学家易犯的十大编码错误,你中招了吗?

据科学家比软件工程师擅长统计,又比统计学家擅长软件工程。听起来牛逼轰轰,事实却是,许多数据科学家有统计学背景,却没有什么软件工程方面的经验,因此在编码时容易犯一些简单的错误。作为一名高级数据科学家,本文作者总结了他在工作中常见数据科学家犯的十大错误。

我是一名高级数据科学家,在 Stackoverflow 的 python 编码中排前 1%,而且还与众多(初级)数据科学家一起工作。下文列出了我常见到的 10 个错误。

没有共享代码中引用的数据

数据科学需要代码和数据。所以为了让其他人能够复现自己做出来的结果,你需要提供代码中涉及的数据。这看起来很简单,但许多人会忘记共享代码中需要的数据。

import pandas as pd
df1=pd.read_csv('file-i-dont-have.csv') # fails
do_stuff(df)

解决方案:用 d6tpipe 共享代码中的数据文件,或者将数据文件上传到 S3/网页/Google 云等,还可以将数据文件保存到数据库中,以便收件人检索文件(但不要将数据添加到 git 中,这一点后面的内容会讲到)。

硬编码其他人无法访问的路径

和错误 1 类似,如果硬编码其他人无法访问的路径,他们就没法运行你的代码,而且在很多地方都必须要手动修改路径。Booo!

import pandas as pd
df=pd.read_csv('/path/i-dont/have/data.csv') # fails
do_stuff(df)
# or 
impor os
os.chdir('c:\\Users\\yourname\\desktop\\python') # fails

解决方案:使用相对路径、全局路径配置变量或 d6tpipe,这样其他人就可以轻易访问你的数据了。

将数据和代码混在一起

既然数据科学代码需要数据,为什么不将代码和数据存储在同一个目录中呢?但你运行代码时,这个目录中还会存储图像、报告以及其他垃圾文件。乱成一团!

├── data.csv
├── ingest.py
├── other-data.csv
├── output.png
├── report.html
└── run.py

解决方案:对目录进行分类,比如数据、报告、代码等。参阅 Cookiecutter Data Science 或 d6tflow 项目模板,并用问题 1 中提到的工具存储以及共享数据。

  • Cookiecutter Data Science:https://drivendata.github.io/cookiecutter-data-science/#directory-structure
  • d6tflow 项目模板:https://github.com/d6t/d6tflow-template

用 Git 提交数据

大多数人现在都会版本控制他们的代码(如果你没有这么做那就是另一个问题了!)。在共享数据时,可能很容易将数据文件添加到版本控制中。对一些小文件来说这没什么问题。但 git 无法优化数据,尤其是对大型文件而言。

git add data.csv

解决方案:使用问题 1 中提到的工具来存储和共享数据。如果你真的需要对数据进行版本控制,请参阅 d6tpipe、DVC 和 Git Large File Storage。

  • DVC:https://dvc.org/
  • Git Large File Storage:https://git-lfs.github.com/

写函数而不是 DAG

数据已经讨论得够多了,接下来我们谈谈实际的代码。你在学编程时,首先学的就是函数,数据科学代码主要由一系列线性运行的函数组成。这会引发一些问题,详情请参阅「4 Reasons Why Your Machine Learning Code is Probably Bad。」

  • 地址:https://towardsdatascience.com/4-reasons-why-your-machine-learning-code-is-probably-bad-c291752e4953
def process_data(data, parameter):
 data=do_stuff(data)
 data.to_pickle('data.pkl')
data=pd.read_csv('data.csv')
process_data(data)
df_train=pd.read_pickle(df_train)
model=sklearn.svm.SVC()
model.fit(df_train.iloc[:,:-1], df_train['y'])

解决方案:与其用线性链接函数,不如写一组有依赖关系的任务。可以用 d6tflow 或者 airflow。

写 for 循环

和函数一样,for 循环也是你在学代码时最先学的。这种语句易于理解,但运行很慢且过于冗长,这种情况通常表示你不知道用什么替代向量化。

x=range(10)
avg=sum(x)/len(x); std=math.sqrt(sum((i-avg)**2 for i in x)/len(x));
zscore=[(i-avg)/std for x]
# should be: scipy.stats.zscore(x)
# or
groupavg=[]
for i in df['g'].unique():
 dfg=df[df[g']==i]
 groupavg.append(dfg['g'].mean())
# should be: df.groupby('g').mean()

解决方案:NumPy、SciPy 和 pandas 都有向量化函数,它们可以处理大部分你觉得需要用 for 循环解决的问题。

没有写单元测试

随着数据、参数或者用户输入的改变,你的代码可能会中断,而你有时候可能没注意到这一点。这就会导致错误的输出,如果有人根据你的输出做决策的话,那么错误的数据就会导致错误的决策!

解决方案:用 assert 语句检查数据质量。Pandas 也有相同的测试,d6tstack 可以检查数据的获取,d6tjoin 可以检查数据的连接。检查数据的示例代码如下:

  • d6tstack:https://github.com/d6t/d6tstack
  • d6tjoin:https://github.com/d6t/d6tjoin/blob/master/examples-prejoin.ipynb
assert df['id'].unique().shape[0]==len(ids) # have data for all ids?
assert df.isna().sum()<0.9 # catch missing values
assert df.groupby(['g','date']).size().max()==1 # no duplicate values/date?
assert d6tjoin.utils.PreJoin([df1,df2],['id','date']).is_all_matched() # all ids matched?

没有注释代码

我明白你急着做分析。于是你把代码拼凑起来得到结果,把结果交给你的客户或者老板。一周之后他们找到你,问你「你能改掉 xyz 吗?」或「你能更新一下结果吗?」。然后你和自己的代码大眼瞪小眼,既不记得你为什么要这么做,也不记得你做过什么。现在想象一下其他人运行这段代码时的心情。

def some_complicated_function(data):
 data=data[data['column']!='wrong']
 data=data.groupby('date').apply(lambda x: complicated_stuff(x))
 data=data[data['value']<0.9]
 return data

解决方案:即便你已经完成了分析,也要花时间注释一下你做过什么。你会感谢自己的,当然其他人会更加感谢你!这样你看起来会更专业!

把数据存成 csv 或 pickle

说回数据,毕竟我们讨论的是数据科学。就像函数和 for 循环一样,CSV 和 pickle 文件也很常用,但它们其实并没有那么好。CSV 不包含模式(schema),所以每个人都必须重新解析数字和日期。Pickle 可以解决这一点,但只能用在 Python 中,而且不能压缩。这两种格式都不适合存储大型数据集。

def process_data(data, parameter):
 data=do_stuff(data)
 data.to_pickle('data.pkl')
data=pd.read_csv('data.csv')
process_data(data)
df_train=pd.read_pickle(df_train)

解决方案:用 parquet 或者其他带有数据模式的二进制数据格式,最好还能压缩数据。d6tflow 可以自动将数据输出存储为 parquet,这样你就不用解决这个问题了。

  • parquet:https://github.com/dask/fastparquet

使用 Jupyter notebook

这个结论还有一些争议——Jupyter notebook 就像 CSV 一样常用。很多人都会用到它们。但这并不能让它们变得更好。Jupyter notebook 助长了上面提到的许多不好的软件工程习惯,特别是:

  1. 你会把所有文件存在一个目录中;
  2. 你写的代码是自上而下运行的,而不是 DAG;
  3. 你不会模块化你的代码;
  4. 代码难以调试;
  5. 代码和输出会混合在一个文件中;
  6. 不能很好地进行版本控制。

Jupyter notebook 很容易上手,但规模太小。

解决方案:用 pycharm 和/或 spyder。

原文链接:https://medium.com/m/global-identity?redirectUrl=https%3A%2F%2Ftowardsdatascience.com%2Ftop-10-coding-mistakes-made-by-data-scientists-bb5bc82faaee

要:本次分享主要介绍 Hive数据如何迁移到MaxCompute。MMA(MaxCompute Migration Assist)是一款MaxCompute数据迁移工具,本文将为大家介绍MMA工具的功能、技术架构和实现原理,再通过实际操作MMA,演示将Hive数据迁移到MaxCompute。

演讲嘉宾简介:阿里云智能产品专家-云花

精彩视频回顾:Hive数据如何同步到MaxCompute

以下内容根据演讲视频以及PPT整理而成。本次分享主要围绕以下两个方面:一、MMA功能介绍、技术架构和原理二、MMA数据迁移操作演示

一、MMA功能介绍、技术架构和原理1.MMA功能介绍MMA主要覆盖的场景包括批处理,存储,数据集成,作业编排及调度。MMA提供迁移评估分析功能,自动化生成迁移评估报告。迁移评估报告会报告出从Hive表的数据结构到MaxCompute的数据结构之间是否有数据类型映射兼容性问题,如语法问题。MMA支持自动化数据迁移功能,支持批量建表以及数据自动化批量迁移。另外,MMA还支持作业语法分析,可以检查Hive SQL能否直接运行在MaxCompute里。MMA还支持工作流迁移,对主流数据集成工具Sqoop进行作业的迁移转换,并自动创新DataWorks数据继承作业。

2.MMA迁移服务架构MMA迁移服务架构如下图。左侧是客户Hadoop集群,右侧的是Aliyun 大数据服务,主要是DataWorks和MaxCompute。MMA工具会跑在客户的Hadoop集群上,客户的服务器需要能够访问Hive Server。在机器上部署MMA客户端工具时会自动化获取Hive Meta里的数据,既将Hive的Meta数据从MySQL中读出来,还可以将Meta信息自动转换成MaxCompute DDL,然后用DDL在MaxCompute中批量创建表,批量拉起数据同步的作业,向Hive Server并发提交Hive SQL作业。基于Hive SQL作业调用一个UDF,UDF里面会集成Tunnel的SDK,基于Tunnel将数据批量写到MaxCompute的表中。作业和工作流的迁移也是基于MMA客户端工具自动发现的Hive Meta数据,做工作流的作业检查,包括把工作流的组件中的工作流的配置批量转换成DataWorks工作流的配置,直接生成DataWorks工作流。以上步骤完成了数据到作业到工作流的迁移。最后一步是迁移完成后需要基于MaxCompute和DataWorks架构对接业务系统。

3.MMA Agent技术构架和原理通过客户端和服务端,MMA可支持数据和工作流的批量迁移。安装在客户服务器上的MMA客户端工具包含下图中的四个能力。首先可自动获取Hive Metadata,并自动创建生成DDL和UDTF,而且可批量创建表和批量Hive数据迁移。相应的,MMA有四个主要组件。Meta Carrier工具自动将Hive Meta信息提取出来,在本地生成Hive Meta结构。Meta Processor是基于Meta Carrier工具产出的结果,基于Hive Meta数据批量转成MaxCompute的DDL,既批量转成建表语句和数据类型的转换。此外,MMA客户端工具还内置了ODPS Console,基于ODPS Console将Meta Processor产出的ODPS DDL在MaxCompute上批量创建表。最后基于Data Carrier批量创建Hive SQL作业。每个Hive SQL作业相当于多个表或者多个分区并行的数据的同步。

二、MMA数据迁移操作演示1.环境准备如下图所示,MMA环境运行要求是jdk1.6版本以上,Python3+。另外,运行MMA的机器,通过Hive Client提交Hive SQL的作业。机器还需要可以访问Hive Server,并连接MaxCompute服务。下图右侧的场景案例是客户在基于MMA做同步数据时发现的问题。例子中客户有自己的IDC,在阿里云有自己的ECS,客户从IDC拉一条专线访问阿里云。在安装MMA之前,客户可以从ECS上直接访问MaxCompute,但IDC里的机器不能访问MaxCompute。此时需要在这条专线上增加VBR路由配置,既在边界路由上增加一个配置。配置之后可以打通从IDC到ECS,甚至到MaxCompute服务的网络访问。

2.下载和编译工具包下载编译工具包有两种方法。一是下载下图中编译好的工具包。此外,由于用户的Hive版本各不相同,用户可以根据MMA官网上提供的GitHub地址下载源码,拉到本地进行编译。

3.MMA Agent操作说明使用meta-carrier采集Hive Metadata:机器提前安装好Hadoop环境,本地有Hive Server。提前下载客户端的odps-data-carrier.zip包,并在本地解压。解压完成后会显示下图所示目录。bin目录下有几个文件,首先是MMA的几个核心角色:meta-carrier、meta-processor、odps_ddl_runner用于批量创建表,hive_udtf_sql_runner用于同步数据。libs目录下是工具依赖的jar包和库。 res目录的console目录下的bin目录包含odpscmd,是MMA客户端的工具,odps_config,ini配置文件。本地Hive上面有三个库,其中dma_demo库下有五个表,可将五个表自动批量同步到MaxCompute上。首先需要在MaxCompute上创建一个project,既在DataWorks控制台创建一个空Project。打开新的命令窗口,在本地运行的ODPS Command客户端工具,连接新创建的空的project。在已经安装了MMA Hive的机器上运行,解压,进入odps-data-carrier工具的目录。执行 bin/meta-carrier -h查看其参数说明,-d表示用户可以指定数据库,通过指定数据库提取meta数据,若不指定,会将Hive下所有的库的meta都拉取出来。-o指定输出目录,-t参数指定表,-u参数指定uri地址,即Hive Meta的地址。开始测试时首先指定地址,因为是thirft地址,所以用thirft协议连接。此外由于Hive Meta在本地,所以只需要将dma_demo库的meta拉取出来,加-o参数,指定目录。通过tree meta可以查看meta目录结构。meta目录下生成和数据库同名的dma_demo目录。dma_demo目录下的json文件是描述数据库meta信息的文件。partition_meta里面的两个表是分区表,table_meta的表是非分区表,会把所有表集的meta信息写在下面。

使用network-measurement-tool:网络测量工具network-measurement-tool用于网络测速,测量Hive集群到MaxCompute各region的网络连通质量。通过网络测速可以知道网络传输速度和大概的数据量,根据网络传输速度预估数据传输时间。network-measurement-tool工具连接MaxCompute上所有region的节点ENDPOINT地址,由最快到最慢做测速排序。下图中执行结果最快的是HANGZHOU,连接时间为51ms,最慢的是一个海外region KUALA_LUMPUR,连接时间为3393ms。

使用sql-checker检查Hive SQL是否可以直接在MaxCompute上执行:sql-checker可用于检查Hive SQL语法兼容性,判断SQL能否直接在MaxCompute上运行。其参数input要指定meta目录,指定缺省project和sql参数。若执行结果返回其兼容性OK,即此sql语句可以直接在MaxCompute上运行。

使用meta-processor生成ODPS DDL和Hive UDTF SQL:通过第一步已经拉出了Hive Meta库的metadata信息。下一步需要将Hive Meta转换成MaxCompute DDL。使用bin/meta-processor -h查看参数。-i即input,-o是output目录。bin/meta-processor的-i就是第一个命令的输出结果,代表meta的目录,存放的是carrier拉出的Hive Meta数据。指定-i meta -o output。将bin/meta-processor运行结果放入output中。生成output目录。tree output可查看结构。output目录下也会生成一个以MaxCompute的project命名的dma_demo目录。dma_demo目录下面有一个hive_udtf_sql目录,目录下面的.sql用于批量数据迁移。还包含odps_ddl目录,用于后续批量创建表,目录下的.sql是创建表的语句。

使用odps_ddl_runner.py批量创建表和分区:既然DDL已经生成,下一步需要批量创建表。批量创建表依赖MaxCompute的命令行工具(客户端工具)。工具包一级目录下的odps_config包含几个基本参数,其中project_name、access_id、access_key、end_point为必填项。配置完成可以开始批量创建表。批量创建表工具要执行Python命令,python36 bin/odps_ddl_runner.py -h。参数中input参数由meta processer自动生成,odpscmd参数不是必须指定的,它会默认找到所在目录,不需要单独配置参数。创建表过程要拉起odps_command工具,基于客户端工具来向MaxCompute提交建表语句。通过show table查看是否创建了五个表,再查看分区是否也建好。若Hive和MaxCompute上的分区创建完成,两边的表结构也应相同。

使用hive_udtf_sql_runner.py迁移数据:通过命令行python36 bin/hive_udtf_sql_runner.py开始读output目录下的.sql语句。查看python36 bin/hive_udtf_sql_runner.py命令的参数,Input_all会批量迁移output下所有数据。若只想做单表的迁移或者单分区的迁移,需要使用input_single_file参数。parallelism参数表示并行度。数据迁移完成后在MaxCompute中查看表中是否有数据。对比MaxCompute中的数据和Hive中对应表的数据。若其size相同,Hive和MaxCompute中对应表的数据相同,说明已经完整迁移数据。

进阶功能1:仅生成指定的database或table的metadata:在生成meta时可以不生成整个数据库的meta,可以指定一个表,生成一个表的meta。Meta carrier 工具提供了抓取指定数据库可表的能力。

进阶功能2:进灵活的hive到MaxCompute映射:如果用户需要自定义MaxCompute上的表,可以更改命名,加前缀或后缀,修改自定义字段名。如可以修改MaxCompute DDL里的json文件实现表名或字段名的自定义。

进阶功能3:单表或单分区迁移:上面的例子中已经批量迁移五张表,通过drop table inventory,演示单分区迁移。首先若只需同步一个分区的数据,需要重新创建一张表。执行python36 bin/odps_ddl_runner.py创建表,指定其output目录,开始批量创建表。此时inventory表以及其五个分区已经创建完成。但创建的分区中没有数据,可指定其中一个分区,如第二个分区。通过使用input_single_file参数,指定具体分区的sql目录。可指定目录为output/dma_demo/hive_udtf_sql/single_partition/inventory_1.sql。执行完成后查看结果,对比在Hive上第二分区的数据和迁移进MaxCompute的单分区的数据,若两个单分区数据一致,则表示迁移完成。

4.使用DataWorks自动迁移数据和工作流MMA1.0版本还未将工作流迁移做成服务化功能,目前还是一个线下工具。客户需要根据下图模板生成相应目录。在做工作流迁移时,如果使用开源组件,可以按照模板将配置放到相应目录下。如果不使用开源组件,如自研的工作流调度编排服务,可基于标准化模板,按照模板的目录结构生成用户自己的工作流数据,打成zip包上传到DataWorks。目前MMA1.0还需要客户手动打包文件上传zip包,后台会进行自动解析并加载到DataWorks工作流。上传完成后,DataWorks服务会根据ODPS DDL 批量生成MaxCompute的table。MaxCompute表创建后,DataWorks服务会自动拉起DataX的数据同步任务,完成批量数据迁移。

下图是可配置的项目描述文件project.xml,其中project信息可以自定义。另外一个是工作流描述文件,workflow.xml中是工作流自定义的参数,用户可以通过编辑配置文件进行修改。

5.其他类型作业的迁移方案UDF、MR迁移:用户直接将jar包上传到MaxCompute上,开启2.0支持,开启对Hive兼容的flag。将Hive兼容的flag设置为true,再在MaxCompute下直接迁移Hive下的UDF和MR。需求注意不支持UDF,MR中直接访问文件系统,网络访问和外部数据源连接。外表迁移:原则上能结构化的数据尽量迁移到MaxCompute内部表。如果必须通过外表访问外部文件,建议先将数据从HDPS迁移到OSS或OTS,再在MaxCompute中创建外部表,实现对文件的访问。Spark作业迁移:MMA对开源Spark的语法完全兼容。用户只需要下载Spark On MaxCompute客户端,在编写Spark SQL时仅增加MaxCompute的连接参数,其它部分和Spark SQL的语法相同。

6.查看迁移评估报告创建MaxCompute DDL完成后,除了生成DDL会SQL以外,还会生成迁移评估报告report.html文件。迁移评估报告是一个兼容性报告,显示Hive表的数据结构和MaxCompute表的数据结构之间的映射关系是否有风险,并标识风险等级。另外会给出明细说明以及预警提示,如数据类型不兼容或语法不兼容等。用户在迁移之前可以查看此报告评估迁移风险。


查看更多:https://yqh.aliyun.com/detail/6648?utm_content=g_1000106727

上云就看云栖号:更多云资讯,上云案例,最佳实践,产品入门,访问:https://yqh.aliyun.com/

口测试【接口:系统与系统之间,组件与组件之间,数据传递交互的通道】

一、简介

1.1接口概念:指的是系统或组件之间的交互点,通过这些交互点可以实现数据的交互;可分为硬件接口和软件接口;

服务器开了个口,客户端发送请求

1.2接口的类型:

①按协议划分:http、tcp、ip②按语言划分:C++、java、php

③按范围划分,系统之间的接口和程序内部的接口

系统之间的接口:多个内部系统之间的交互【用户系统、订单系统、商品系统】,内部系统与外部系统【支付系统】之间的交互

程序内部的接口:方法与方法之间,函数与函数之间【传入不同的数据,输出不同的值,叫接口函数】,模块与模块之间的交互

1.3接口测试的概念

接口测试:对系统或组件之间的接口进行测试,校验传递的数据正确性和逻辑依赖关系(淘宝先登录才能看订单,即使复制了订单的网页,但是未登录,复制的订单网页打开还是跳转登录界面。)的正确性。【校验数据的交换、传递和控制管理的过程,以及相互逻辑依赖关系。】

1.4接口测试原理【接口测试主要测试目标:服务器,功能测试:测试客户端】

1>怎么测?模拟客户端,向服务器发送请求

2>用什么测?工具:fiddler、postman、jmeter;代码:python+UnitTest框架+Requests框架

3>测试什么?测试服务器针对客户端请求,回应的响应数据是否与预期结果一致

1.5特点

①测试可以提前介入,提早发现bug,符合质量控制前移的理念

②可以发现一些页面操作发现不了的问题

③接口测试低成本高效益(底层的一个bug能够引发上层8个左右bug,接口测试可以实现自动化)

④不同于传统的单元测试,接口测试是从用户的角度对系统进行全面的检查

1.6实现方式

工具:fiddler、postman、jmeter;代码:python+UnitTest框架+Requests框架

1.7自动化接口测试

接口自动化测试:借助工具、代码,模拟客户端发送请求给服务器,借助断言自动判断 预期结果和实际结果是否一致。【是让程序或工具代替人工自动地完成对接口进行测试的一种过程】

二、HTTP协议

(超文本传输协议,基于请求与响应模式的,应用层协议,也是互联网上应用最为广泛的一种协议)【端口是用来找到应用】

2.1 协议:就是规则。要求通信的双方必须严格遵守。

2.2 特点

①支持客户端/服务器模式 ②简单快速 ③灵活 ④无连接 ⑤无状态

2.3 URL(Uniform Resource Locator)统一资源定位符,是互联网上标准资源的地址。HTTP使用URL来建立连接和传输数据。

作用:在网络环境中,唯一的定义一个数据资源

2.4 URL语法格式(组成)【http:80;https:443】

http[协议] :// xxxxx[域名] : xxxx[端口:0~65535] / xxxxxx[资源路径] ? xx[k=value]&xx&x[查询参数]

协议:规定数据传输的方式

域名:在网络环境中找到主机 用://与协议分隔

端口(port)【常省略】:在网络主机上,标识一个进程(运行起来的应用程序) 本地主机用PID标识 用 :与域名分隔

资源路径:标识网络资源(文件、图片、音视频、变量.....) 用/与端口分隔

查询参数:参数传递给资源路径 用?与资源路径分隔,内部用&分隔

【当资源路径没有时,可以认为是“/”】

2.5 HTTP请求【请求包;请求报文】

1>作用:

客户端(app、浏览器),发送请求给服务器时,使用的协议--http请求协议

规定发送给服务器的数据传输的语法格式

2>整体格式

第一行:请求行:请求方法(空格)url(空格)协议版本

第二行:请求头:语法格式 【格式:key:value】

user-agent:描述发送端的本地浏览器类型

Content-Type:xxxx(描述请求体的数据类型)通常碰到form(表单类型)和json类型

空行:代表http请求头结束,请求体开始

请求体:请求发送时携带的数据。 数据类型(Content-Type)的值【post、put(相当于修改)有请求体,get、delete没有请求体】

3>fiddler抓包验证

先清空fiddler--访问网站--点开(一般第一条)请求--点击【raw】

4>请求行

http请求方法(大小写无所谓)【对应数据库增删改查】

GET:查询

POST:添加(常用在登录)

PUT:修改

DELETE:删除

5>请求头

语法格式:k:v

user-agent:产生请求浏览器类型

Content-Type:请求体数据类型

application/json:JSON数据格式(k:v)

application/x-www-form-urlencoded:form表单数据


6>请求体

数据值的组织形式,受Content-Type的值影响

k=v格式

get、delete方法没有请求体

post、put方法有请求体

2.6 HTTP响应

1>作用:服务器端,针对客户端发送的http请求,回发响应数据。 --http应答

规定回发给客户端的数据组织格式

2>整体格式【响应包;响应报文】

响应行(状态行):协议版本(空格)状态码(空格)状态描述【状态码和状态描述捆绑,状态码对应状态描述】

响应头:语法格式:k:v

Content-Type:描述响应体中数据类型

空行:代表响应头结束

响应体:绝大多数情况不为空(请求成功:回发数据,失败:回发错误数据)

数据类型受Content-Type值影响

3>状态码【有三位数字组成,第一个数字定义响应的类别】

1xx:指示信息--表示请求已接收,等待继续处理

**2xx:成功--表示请求已被成功接收、理解、接受:eg:200、201

3xx:重定向--待访问的资源,需求重新指定路径访问。【要完成请求必须进行更进一步的操作】

**4xx:客户端错误--请求有语法错误或请求无法实现 eg:404【请求文件不存在】/403【请求文件存在但拒绝被访问,也就是说没有权限访问】

5xx:服务器端错误--服务器未能实现合法的请求

4>状态码描述

一般与状态码唯一对应

5>响应头

语法格式:k:v

Content-Type:值为响应体的数据类型

Content-Length:响应体的大小【可不写,浏览器自动求取,一旦写,必须准确】

6>响应体(测试中的实际结果,预期结果从接口文档中来)

就是响应的消息体,数据可以是普通文本、XML、JSON、HTML源码

三、接口测试风格

1>传统风格

对用户进行操作的相关接口,包括增删改查

操作

请求方式

URL

成功状态

查询某个用户

GET/POST

http://127.0.0.1:8080/myweb/user/getUser?id=1

http://127.0.0.1:8080/myweb/user/getById?id=1

http://127.0.0.1:8080/myweb/getUserById?id=1

200

查询所有用户

GET/POST

http://127.0.0.1:8080/myweb/user/getUserList

http://127.0.0.1:8080/myweb/user/getUsers

200

添加用户

POST

http://127.0.0.1:8080/myweb/user/addUser

200

修改用户

POST

http://127.0.0.1:8080/myweb/user/updateUser

200

删除用户

GET/POST

http://127.0.0.1:8080/myweb/user/deleteUser?id=1

200

特点:

请求方法,只使用get和post即可

URL不唯一,不重复。同一个操作可以对应不同的URL

状态码的使用较单一。200最常见

2>RESTful风格接口【一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件】

REST:即(Representational State Transfer)的缩写,词组翻译是“表现层状态转化”【同一URL,对应的方法不同,对应的操作也不同】,如果一个架构符合REST原则,就称它为RESTful架构。

操作

请求方式

URL

成功状态

查询某个用户

GET

http://127.0.0.1:8080/myweb/users/1

200

查询所有用户

GET

http://127.0.0.1:8080/myweb/users

200

添加用户

POST

http://127.0.0.1:8080/myweb/users

201

修改用户

PUT

http://127.0.0.1:8080/myweb/users/1

201

删除用户

DELETE

http://127.0.0.1:8080/myweb/users/1

204

架构特点:

1.每一个URL代表一种资源;

2.客户端和服务器之间,传递这种资源的某种表现层;

3.客户端通过四个HTTP动词,对服务器端资源进行操作,实现“表现层状态转换”(数据的不同表现形式,图像、文字表现同一个数据对象)

4.接口之间传递的数据最常用格式为JSON。

四、接口测试流程

  1. 需求分析:主要依据需求文档(产品)
  2. 接口文档解析:一般是由开发人员编写的接口文档(API文档)
  3. 设计接口测试用例(根据接口文档产生用例,送审)
  4. 执行测试用例:使用接口测试工具实现(postman、jmeter);通过编写代码实现(python+requests+unittest)
  5. 接口缺陷的管理和跟踪
  6. 生成测试报告
  7. 接口自动化持续集成(可选)

五、接口文档的作用和展现形式

5.1接口文档

1>接口文档:又称为API文档,一般是由开发人员所编写的,用来描述系统所提供接口信息的文档。大家都根据这个接口文档进行开发,并需要一直维护和遵守。

2>作用

1.能够让前端开发与后台开发人员更好的配合,提高工作效率。(有一个统一参考的文件)

2.项目选代或者项目人员更迭时,方便后期人员查看和维护

3.方便测试人员进行接口测试

  1. 展现形式

【错误码:不是错误,与http状态码区分开,其实是状态码,描述状态】

形式:word文档形式、Excel表格式形式、pdf文档

  1. 结构

基本信息:

Path:对应url里的资源路径(url前面的协议等在接口文档的系统信息里呈现)

Method:PUT/POST/DELETE/GET

接口描述:。。。。。

请求参数:

Headers(请求头):数据类型(k【Content-Type】:v【application/json】)

Body(请求体):实现该接口使用的数据以及对应类型。

返回数据(预期结果):成功和失败的状态码

状态码:200 成功:状态码200

错误码(自定义状态码):码值和描述信息 失败:错误码(自定义状态码)

5.2接口文档解析

接口文档的解析本质:从接口文档中,找出http请求所需要的数据信息,包括:

请求方法URL【行里两个】、请求头(k:v)【Content-Type类型】、请求体【数据:数据类型的名字和类型】(行头体)、响应状态码、描述。

Eg:

请求体:{“数据类型的名字,建议复制文档里的不要用手敲”:“数据值,文档中不知道,可找开发要”}

Fiddler:

K:v是json类型数据

Raw项:方法、url、请求头、请求体

接口用例设计

6.1为什么要写

1.防止测试点漏测、条理清晰

2.方便分配工作,评估工作量和时间

3.面试使用

6.2接口测试的测试点(测试维度)

6.3功能测试

  1. 单接口功能

手工测试中的单个业务模块,一般对应一个接口。

Eg: 登录业务-->登录接口

加入购物车业务-->加入购物车接口

支付业务-->支付接口

.........

借助工具、代码,绕开前端界面,组织接口所需要的数据,展开接口测试。

  1. 业务场景功能

按照用户实际使用场景,梳理接口业务场景。

组织业务场景时,一般只需要做正向测试即可。(与手工一致)

一般建议用最少的用例覆盖最多的业务场景。

Eg:登录---搜索商品---加购物车---下单---支付---评价

6.4性能测试

1>响应时长:发送请求,服务器多久回发响应

2>吞吐量:当前的接口处理用户的请求事物数量

3>并发数:多个用户同时向接口发请求,比如淘宝秒杀

4>服务器资源利用率:CPU、内存、显卡、网络I/O、磁盘I/O

6.5浏览器开发者工具

浏览器的开发者工具:F12或右键检查打开--->Network--->一定要选择ALL--->关于登录,可以在网站界面输入好数据,点击登录按钮--->查看

点击Name下数据--->do_login(与登录按钮对应):

Headers【相当于HTTP响应,组织形式不一样,但是数据该有的都有】:

General:表示总则;包括请求URL、请求方法、状态码(Status Code)、IP地址和端口号(Remote Address)

Response Headers:表示响应头;数据以k:v形式组织

Request Headers:表示请求头;对应HTTP请求头里的信息;数据类型依然k:v形式

Query String Parameters:表示查询字符串参数,对应url后部分的查询参数

Form Data:表单数据;比如登录界面,这部分是登录界面输入的数据

Payload:有一个view source,是请求体的数据,可以直接复制json数据

Response【查看服务器响应返回的结果】

6.6安全测试

1>攻击安全:由专业安全测试工程师完成;

2>业务安全

①敏感数据是否加密:比如密码

②SQL注入:

输入用户名为:‘ or 1=1#,提示用户名格式错误,表示没有SQL注入的漏洞

③其他

6.7与手工测试区别

1>手工测试测写入到输入框中的数据是否正确。接口测试测参数对应的参数值是否正确,相当于k:v。

2>接口测试不单单针对参数值进行测试,还可以针对参数本身进行测试。比如测username本身,用uname:正确的用户名去测试,看看能否通过。

对于参数测:

①正向参数:

必选参数:所有的必填项都包含。

组合参数:所有的必填+任意一个或多个可选参数

全部参数:所有的必填+所有的可选参数

②反向参数:

多参:多出一个或多个必选参数(可以任意指定)

少参:缺少一个或者多个必选参数

无参:没有必选参数

错误参数:参数名输入错误

6.8接口测试文档要素

编号、用例名称(标题)、模块、优先级、预置条件、请求方法、URL、请求头、请求体(请求数据)、预期结果

URL列:写完整URL或者写{协议+域名}/文档里的path内容【path写明确,协议和域名可写成文字,以防后期协议和域名修改,就不用大篇幅修改】

登录界面

  1. 操作成功不代表登录成功,只能说http请求已经被服务端处理了。会出现状态码
  2. 预期结果包括状态码和描述信息;data数据包括当前用户登录的身份,下次只要核对data的值,登录成功会产生令牌(token,隔段时间会变)数据(data的值)表明用户已经登录进去了

登录里的用户名未注册就是不存在

3>数值部分和手工测试一样,参数是接口特有的。

用户名和密码为空不能想当然认为都是用户名或密码错误,要去实践。

登录的信息都是去数据库中比对,如果特殊字符等在数据库中不允许出现,就不用做此类反向测试。要在数据库中组织出不符合的数据,测开发在接收数据的时候,不能依托数据库,而是依托开发的代码有没有校验出来,不符合规范的手机号是否能登录成功。

总结:在接口测试用例中,对于k:v,考虑k的正反向,v保证正确;考虑v的正反向,k保证正确。

业务场景功能

8.1分析测试点

Eg:针对“员工管理”业务场景:登录---添加员工---查询员工(看看是否添加成功)---修改员工---再次查询(看看修改成功)---删除员工---查询员工(看看是否删除)【相当于把多个模块接口串起来,用最少的用例尽可能的覆盖所有接口】

8.2添加用户【测校验的情况:正确、错误、重复】

请求方法:post

URL:

请求头:

请求体:

返回数据:

8.3查询员工【测校验的情况:正确、空值、错误值】

8.4修改员工

8.5删除员工

POSTMAN

  1. 官网下载postman:https://app.getpostman.com/app/download/win64
  2. 下载node.js:https://nodejs.org/zh-cn/download/,为了安装newman
  3. 安装newman:npm install -g newman
  4. 为newman安装newman-reporter-html【newman是postman插件,newman-reporter-html是newman的插件】,安装命令:npm install -g newman-reporter-html

9.1开发者工具

Headers请求方法、request URL、request headers中的content-type【代表数据类型,后面的utf可以不管】、Form data【请求体,k:v对】

Preview返回数据中看不懂的字符,在preview里能找到

Response:看返回数据【汉字的转码在preview里】

9.2Postman使用

Postman:

Headers:填写content-type的k:v值

Body:下拉框选项选择content-type中的v项,然后填入请求体中的k:v对,是json就选择raw【原始】

Send完看响应数据,在body下,选择pretty,把html改成json,就可以看到返回的结果了

结果:

阶段目标划分

Postman管理测试用例collections

  1. 创建collections
  2. Add request:创建用例,添加请求

点击sava或ctrl+s,小红点就没有了

  1. Add folder:创建子目录

用例集导出、导入

  1. export:导出,在用例集名称右侧的三点中,一般默认选项导出
  2. 文件名后缀不可改,文件名不建议修改,只有第一段文字可修改,接口集成时,不可以用中文命名
  3. Import:导入,file->upload files->选文件位置

Postman断言

  1. 断言:让程序判断预期结果与实际结果是否一致。
  2. 特点:postman断言是使用JavaScript语言编写的,写在Tests标签页里【对应框上面有Tests选项】
  3. postman常用断言【在<中选择对应的就可以,代码自动生成】

总体步骤:

  • 在Tests标签中,选择断言方法适当调整test()方法参数1,和匿名函数中的预期结果点击send按钮,发送请求,执行断言代码。查看断言结果

**3.1断言响应状态码

选择:Status code:code is 200

详情:pm.test("Status code is 200", function () {

pm.response.to.have.status(200);

});

解释:

pm:代表postman的一个实例【类下面的一个对象】

test():是pm实例的一个方法。有两个参数

参数1:在断言成功后,给出的文字提示,可以修改。"Status code is 200"

参数2:匿名函数,function () {pm.response.to.have.status(200);}

function代表函数,后面应该放函数名,但是没有,所以是匿名函数;

response代表响应体,to.have应该有

整句话表示:postman的响应结果中应该包含状态码200

200是预期结果

断言的结果在Tests项下Test Results,看到PASS和Status code is 200【对应断言成功后的描述】

3.2断言响应体是否包含某个字符串

选择:Response body:Contains string

详情:pm.test("Body matches string", function () {

pm.expect(pm.response.text()).to.include("string_you_want_to_search");

});

解释:预期结果用返回体内的value值,推荐用message的value

3.3断言响应体是否等于某个字符串(对象)【json花括号括起来是对象,中括号括起来是数组】

选择:Response body:Is equal to a string

详情:pm.test("Body is correct", function () {

pm.response.to.have.body("response_body_string");

});

解释:通常data对应令牌数据会不停地改变,这个字符串是对返回的全部字符串进行判断,一旦有数据不停变化时,断言不通过。

**3.4断言JSON数据

选择:Response body:JSON value check

详情:pm.test("Your test name", function () {

var jsonData=pm.response.json();

pm.expect(jsonData.value).to.eql(100);

});

解释:

var jsonData=pm.response.json(); var jsonData用js语法定义一个变量;jsonData是变量名;pm.response.json()代表响应的json结果,就是响应的数据

pm.expect(jsonData.value).to.eql(100); 预期json结果值等于100相同,value对应响应体中的key


3.5断言相应头【返回的Headers里】

选择:Response headers:Content-Type header check

详情:pm.test("Content-Type is present", function () {

pm.response.to.have.header("Content-Type");

});

解释:响应头中包含Content-Type;可以判定k:v是否正确,断言响应头所对应的value,直接(k,v)

示例:pm.test("Content-Type is present", function () {

pm.response.to.have.header("Content-Type","application/json");

});【在响应的headers中,添加响应头中的key对应的value判定,用,分隔】

Postman断言工作原理

全局变量和环境变量

15.1概念

全局变量:全局变量是全局唯一的,不可重复定义的变量

环境变量:一个变量只能属于某个环境,在某一个环境中变量不可重复定义;在环境与环境之间可以定义重复的变量;一个环境可以包含多个环境变量;常见环境分类:开发环境、测试环境、生产环境【一个项目生产部署上线】

15.2设置变量

全局变量:

  • 手动设置代码设置:pm.globals.set(“var_name”,value);【变量名必须要双引号】

环境变量:

  1. 手动设置
  2. 代码设置:pm.environment.set(“var_name”,value);

15.3获取变量【请求参数是从params、headers、url中拿出来的,只要从界面中获取的[相当于从两个请求的postman界面中获取的];请求参数只能用在请求参数中,不可以用在代码区域{tests、请求前置脚本},可用在params、headers、bodys

全局变量:

  • 请求参数中获取:{{var_name}}代码中获取:var value=pm.globals.get(“var_name”);【取的时候只要变量名】

环境变量:

  1. 请求参数中获取:{{var_name}}
  2. 代码中获取:var value=pm.environment.get(“var_name”);【取的时候只要变量名】

【获取都用要一个变量去接收,多级的要一级一级取】

请求前置脚本

16.1地位:在send按钮点击后,请求前置脚本代码,第一时间被执行。在postman内部实际http请求之前。

16.2时间戳

概念:对应绝对时间----从1970年1月1日00:00:00到现在所经历的秒数

16.3案例

调用百度首页接口,传时间戳给服务器

实现步骤:

①拿到时间戳写入全局变量

//拿到时间戳数据值

var timestamp = new Date().getTime()

//将时间戳设置到全局变量中

pm.globals.set("glb_timestamp",timestamp)

②点击send按钮,发送请求。请求发送前执行上述代码,写入全局变量

③查看写入的变量:点击眼睛图标

④在请求参数(界面)中,使用全局变量。{{var_name}}【params是查询参数】

⑤在postman控制台,查看发送的http请求

【send发送请求之前会执行请求前置脚本,写进全局变量当中,再发送请求】

Postman关联

17.1介绍:应用于多个http请求之间,有数据关联、或依赖关系时。

17.2实现步骤

A接口依赖B接口的数据

①向B接口发送http请求,获取数据

②将数据保存至全局变量(环境变量)中

③A接口获取全局变量(环境变量)中数据值,进行使用

17.3案例

请求获取天气接口,提取响应结果中的城市,将城市名,给百度搜索接口使用

①发送天气接口请求,在天气接口的Tests中获取城市名,再把城市名写入

//获取全部响应结果

var jsondate=pm.response.json()

//从响应结果中,获取城市名

var city=jsondate.一级一级往下引用k名

//将城市名写入到全局变量

pm.globals.set(“city”,city)

【点击send按钮,发送请求,查看设置的全局变量。点击小眼睛,看全局变量名和全局变量值】

//修改百度搜索请求,使用全局变量,按城市名进行搜索

Postman测试报告

18.1批量执行用例集

Data:引入外部文件

18.2生成测试报告(newman)【在dos界面】

1.先把用例集执行,run

2.导出用例集

3.生成测试报告

①{ newman run 测试脚本文件【导出的json文件】}[可单独执行] -e 环境变量文件【没有环境变量就省略】 -d 测试数据文件 -r html【必写】 --reporter-html-export report.html【报告名称,report名可以修改】

Postman读取外部数据文件(参数化)

比如:登录接口,测一个用户,请求体的数据是写死的,要是测1000个用户,需要用到参数化】

【当http请求,使用的数据有较高相似度时,相同的请求时,考虑使用参数化(将数据组织到数据文件中)】

19.1数据文件简介

CSV:

优点:数据组织形式简单,适用于大量数据的场合

缺点:不支持bool类型数据(数据被postman读入后,自动添加“”包裹bool值);不支持多参、少参、无参、错误参数的接口测试;不支持复杂数据类型(如嵌套字典、列表)

【数值直接拿去用,非数值都加上“”】

JSON:

优点:支持bool类型;支持多参、少参、无参、错误参数的接口测试;支持复杂数据类型(如嵌套字典、列表)

缺点:对于相同的数据量,JSON数据文件大小要远大于CSV文件

19.2导入外部数据文件

CSV:【一定要utf8编码】

①创建XXX.CSV数据文件

②将数据写入到CSV文件中:第一行写入的是数据对应的字段名;从第二行向后依次是对应的数值,数据间用英文,分隔

③在Postman中,选中使用数据文件的用例集,导入数据文件【run->data:select file->选择导入文件->通过preview预览按钮,校验数据文件是否正确】

JSON:【可在json.cn网站里编写,编写好复制粘贴到记事本打开的json文件中】

①创建XXX.JSON数据文件

②在数据文件中,按json语法写入json数据。Postman要求,json格式的数据文件,数据内容的最外层,必须是[ ]。内部所有的数据用{ }存储

③在Postman中,选中使用数据文件的用例集,导入数据文件【run->data:select file->选择导入文件->通过preview预览按钮,校验数据文件是否正确】

建议书写json数据时,无论是不是字符串,都可以用” ”包裹value值

19.3读取数据文件数据

1.方法

①请求参数(请求行、请求头、请求体)中,使用数据文件中的数据

使用{{}}包裹csv文件字段名或json文件中的key

②代码(断言、请求前置脚本)中,使用数据文件中的数据

需要借助postman提供的关键字data点【.】csv文件字段名或json文件中的key

【send不能读外部数据文件,用到外部数据文件了,读取要进入到run里,通过run参数化用例集的按钮批量执行。如果有异常,借助控制台。】

小结:借助数据文件,实现“数据驱动”。有多少条数据,对应就有多少个http请求。

19.4生成测试报告

步骤:

①批量执行测试用例(借助数据文件)

②导出测试用例集(建议与数据文件放在一起)

③执行生成测试报告的命令

Newman run 用例集名称.json -d 数据文件名.csv/.json -r html --reporter-html-export 报告名称.html

项目环境说明

拿到一个项目,要对项目整体有个认识:熟悉项目的功能;了解项目组织架构和相应技术。

20.1功能模块:XXXXXX【模块功能列出】

20.2技术栈

前端:页面显示........

后端:spring全家桶;mysql【实现数据持久化存储,断电也不会丢】+redis【缓存存储数据,读取快】+rabbitmq【消息队列,完成数据通信】

20.3技术架构图(比较详细展开描述技术栈)

20.4初始化项目环境(利用postman)

  1. 新建用例集(不同的模块对应添加子目录)
  2. 创建环境变量(选择Enviroments->create enviroment)

①先创建环境,给环境取名【测试、开发、生成】

②initial value:在外部数据文件中使用,current value:在postman中使用

【注意】:设置了环境,在执行用例的时候要选择对应环境

20.5数据依赖

1.登录成功,返回的“令牌”,被增删改查功能接口依赖

2.添加完的数据id,会被查、改、删依赖

【借助关联和环境变量实现】

20.6提取令牌

1.登录完成,返回data,不是完整令牌,缺少前缀

2.实现:

①发送http登录请求,在响应体中得到data值

var json_data = pm.response.json()

var env = json_data.data.token

②将data值拼接“Bearer”和“空格”,组成一个合法令牌

pm.environment.set("env","Bearer"+" "+env)

③将令牌写入环境变量中。(在Tests中通过代码写入)

20.7生成测试报告

1.在environment中有环境,要先导出环境

2.将环境文件与测试用例集放置到同一目录下

3.执行命令

663