行业测试数据-案例分享

一 总体介绍

“人类正从IT时代走向DT时代”

1.数据测试指的是检查局部数据结构时为了保证临时存储在模块内的数据在程序执行过程中完整、正确的过程。2.工程师开发完成后,常常需要制造大批量的伪数据,来测试数据中台的开发效果。例如在数仓开发中,会遇到需要在已构建的数仓模型(各种表)中,导入一些测试数据,方便逻辑开发完之前进行开发和测试。亦或是自己有一些SQL逻辑需要测试,需要批量造一些假数据(几百上千条,甚至几十万条)。

如何在造数过程中保障数据质量,优化数据产出

数据质量问题:数据一致性,数据完整性、数据准确性、数据唯一性、数据关联性、数据及时性

数据准确性:用于分析和识别无效或者不准确的数据,不可靠的数据可能会导致严重的问题。数据唯一性:用于识别和度量重复数据、冗余数据,重复数据是导致业务无法协同、流程无法追溯的重要因素,是需要解决的最基本的数据问题。数据完整性:唯一性约束不完整、参照不完整;数据条目不完整、数据记录丢失或不可用;不完整的数据所能借鉴的价值就会大大降低,也是数据质量问题最为基础和常见的问题。数据一致性:多源数据的数据模型不一致,例如:命名不一致、数据结构不一致、约束规则不一致。数据实体不一致,例如:数据编码不一致、命名及含义不一致、分类层次不一致、生命周期不一致……。相同的数据有多个副本的情况下的数据不一致、数据内容冲突的问题。数据关联性:数据关联性问题是指存在数据关联的数据关系缺失或错误,例如主外键关系、索引关系等。会直接影响数据分析的结果。数据及时性:能否在需要的时候获到数据,数据的及时性与企业的数据处理速度及效率有直接的关系,是影响业务处理和管理效率的关键指标。

实时数据类:

源头数据订阅-》流式计算计算平台-〉数据输出在线存储系统

2、 逻辑正确性:

本地测试:模拟实时数据流,校验输出结果是否正确

3、数据准确性:

本地逻辑校验通过后,对真实数据进行校验。把实时数据拖回ODPS,做离线的查询、统计、对比

4、时效性:

关注日志时间和表数据产生时间,不能与实际时间偏差太大

二 语言简介

1.什么是python

Python是一种开源的 、解析性的,面向对象的编程语言。

Python使用一种优雅的语法,可读性强 Python支持类和多层继承等的面向对象编程技术。

Python可运行在多种计算机平台和操作系统中,如unix,windows,MacOS,ubuntu,OS/2等等

Python 标识符

在python里,标识符有字母、数字、下划线组成。在python中,所有标识符可以包括英文、数字以及下划线(_),但不能以数字开头。python中的标识符是区分大小写的。以下划线开头的标识符是有特殊意义的。以单下划线开头(_foo)的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用"from xxx import *"而导入;以双下划线开头的(foo)代表类的私有成员;以双下划线开头和结尾的(foo)代表python里特殊方法专用的标识,如__init()代表类的构造函数。

Python保留字符

下面的列表显示了在Python中的保留字。这些保留字不能用作常数或变数,或任何其他标识符名称。所有Python的关键字只包含小写字母。

and exec notassert finally orbreak for passclass from printcontinue global raisedef if returndel import tryelif in whileelse is withexcept lambda yield

多行语句

Python语句中一般以新行作为为语句的结束符。但是我们可以使用斜杠( \)将一行的语句分为多行显示。

语句中包含[], {} 或 () 括号就不需要使用多行连接符。

Python 引号和注释

2.Python 接收单引号(' ),双引号(" ),三引号(''' """) 来表示字符串,引号的开始与结束必须的相同类型的。其中三引号可以由多行组成,编写多行文本的快捷语法,常用语文档字符串,在文件的特定地点,被当做注释。

3.Python中单行注释采用#开头

python 中多行注释使用三个单引号(''')或三个双引号(""")

多个语句构成代码组缩进相同的一组语句构成一个代码块,我们称之代码组。像if、while、def和class这样的复合语句,首行以关键字开始,以冒号( : )结束,该行之后的一行或多行代码构成代码组。我们将首行及后面的代码组称为一个子句(clause)。

4.Python数据类型

准数据类型在内存中存储的数据可以有多种类型。例如,person.s年龄作为一个数值存储和他或她的地址是字母数字字符存储。Python有一些标准类型用于定义操作上,他们和为他们每个人的存储方法可能。Python有五个标准的数据类型:Numbers(数字)String(字符串)List(列表)Tuple(元组)Dictionary(字典)

Python数字数字数据类型用于存储数值。他们是不可改变的数据类型,这意味着改变数字数据类型会分配一个新的对象。Python支持四种不同的数字类型:

int(有符号整型)

long(长整型[也可以代表八进制和十六进制])

float(浮点型)

complex(复数)

Python 支持四种不同的数值类型:整型(Int)- 通常被称为是整型或整数,是正或负整数,不带小数点。长整型(long integers)- 无限大小的整数,整数最后是一个大写或小写的L。浮点型(floating point real values)- 浮点型由整数部分与小数部分组成,浮点型也可以使用科学计数法表示(2.5e2 = 2.5 x 102= 250)复数( (complex numbers))- 复数由实数部分和虚数部分构成,可以用a + bj,或者complex(a,b)表示, 复数的实部a和虚部b都是浮点型。

Python字符串字符串或串(String)是由数字、字母、下划线组成的一串字符。s="a1a2···an"(n>=0)它是编程语言中表示文本的数据类型。python的字串列表有2种取值顺序:从左到右索引默认0开始的,最大范围是字符串长度少1从右到左索引默认-1开始的,最大范围是字符串开头如果你的实要取得一段子串的话,可以用到变量[头下标:尾下标],就可以截取相应的字符串,其中下标是从0开始算起,可以是正数或负数,下标可以为空表示取到头或尾。比如:s = 'ilovepython's[1:5]的结果是love。

5.字符串类型的操作符

序列类型通用的操作符 in, not in, +,等

只适用于字符串的操作符格式化操作符 %

格式化字符 转换方式
%r 优先用repr()函数进行字符串转换
%s 优先用str()函数进行字符串转换
%d / %i 转换成有符号十进制数
%u 转换成无符号十进制数
%o 转换成无符号八进制数
%x / %X 转换成无符号十六进制数(x/X代表转换后的大小写)
%e / %E 转换成科学计数法
%f / %F 转换成浮点数
%% 输出%

当使用以冒号分隔的字符串,python返回一个新的对象,结果包含了以这对偏移标识的连续的内容,左边的开始是包含了下边界。上面的结果包含了s[1]的值l,而取到的最大范围不包括上边界,就是s[5]的值p。加号(+)是字符串连接运算符,星号(*)是重复操作。

6.Python列表List(列表) 是 Python 中使用最频繁的数据类型。列表可以完成大多数集合类的数据结构实现。它支持字符,数字,字符串甚至可以包含列表(所谓嵌套)。列表用[ ]标识。是python最通用的复合数据类型。看这段代码就明白。列表中的值得分割也可以用到变量[头下标:尾下标],就可以截取相应的列表,从左到右索引默认0开始的,从右到左索引默认-1开始,下标可以为空表示取到头或尾。加号(+)是列表连接运算符,星号(*)是重复操作。

7.Python元组元组是另一个数据类型,类似于List(列表)。元组用"()"标识。内部元素用逗号隔开。但是元组不能二次赋值,相当于只读列表。

8.Python元字典字典(dictionary)是除列表以外python之中最灵活的内置数据结构类型。列表是有序的对象结合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取。字典用"{ }"标识。字典由索引(key)和它对应的值value组成

Python数据类型转换有时候,我们需要对数据内置的类型进行转换,数据类型的转换,你只需要将数据类型作为函数名即可。以下几个内置的函数可以执行数据类型之间的转换。这些函数返回一个新的对象,表示转换的值。

9.条件和循环

条件表达式

Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。

Python程序语言指定任何非0和非空(null)值为true,0 或者 null为false。Python 编程中 if 语句用于控制程序的执行,基本形式为:if 判断条件: 执行语句……else: 执行语句……

其中"判断条件"成立时(非零),则执行后面的语句,而执行内容可以多行,以缩进来区分表示同一范围。else 为可选语句,当需要在条件不成立时执行内容则可以执行相关语句

循环控制语句

循环控制语句可以更改语句执行的顺序。Python支持以下循环控制语句:

break语句 在语句块执行过程中终止循环,并且跳出整个循环。

continue语句 在语句块执行过程中终止当前循环,跳出改次循环,执行下一次循环

pass语句 pass是空语句,是为了保持程序结构的完整性

循环表达式

Python的循环语句,程序在一般情况下是按顺序执行的。编程语言提供了各种控制结构,允许更复杂的执行路径。循环语句允许我们执行一个语句或语句组多次。

Python 循环语句实例

10.函数

Python 函数函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。

定义一个函数你可以定义一个由自己想要功能的函数,以下是简单的规则:函数代码块以def关键词开头,后接函数标识符名称和圆括号()。任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。函数内容以冒号起始,并且缩进。return [表达式]结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

语法:

def functionname( parameters ):

​ "函数_文档字符串"

function_suite
return [expression]

默认情况下,参数值和参数名称是按函数声明中定义的的顺序匹配起来的。

实例:

​ 以下为一个简单的Python函数,它将一个字符串作为传入参数,再打印到标准显示设备上。

def printme( str ):

​ "打印传入的字符串到标准显示设备上"

​ print str

​ return

函数调用定义一个函数只给了函数一个名称,指定了函数里包含的参数,和代码块结构。这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从Python提示符执行。如下实例调用了printme()函数:

!/usr/bin/python# -- coding: UTF-8 --

定义函数

def printme( str ):
"打印任何传入的字符串"
print str
return # 调用函数printme("我要调用用户自定义函数!")
printme("再次调用同一函数");

按值传递参数和按引用传递参数所有参数(自变量)在Python里都是按引用传递。如果你在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。

!/usr/bin/python# -- coding: UTF-8 --

可写函数说明

def changeme( mylist ):

mylist.append([1,2,3,4]);
print "函数内取值: ", 
return # 调用changeme函数

mylist = [10,20,30];

changeme( mylist );

传入函数的和在末尾添加新内容的对象用的是同一个引用。故输出结果如下:

函数内取值: [10, 20, 30, [1, 2, 3, 4]]

函数外取值: [10, 20, 30, [1, 2, 3, 4]]

11.python高阶函数map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

!/usr/bin/python# -- coding: UTF-8 -- >>> from functools import reduce>>> def add(x, y):... return x + y...>>> reduce(add, [1, 3, 5, 7, 9])25

!/usr/bin/python# -- coding: UTF-8 -- >>> from functools import reduce>>> def fn(x, y):... return x * 10 + y...>>> reduce(fn, [1, 3, 5, 7, 9])13579

!/usr/bin/python# -- coding: UTF-8 -- # 可写函数说明>>> def f(x):... return x * x...>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])>>> list(r)[1, 4, 9, 16, 25, 36, 49, 64, 81]mylist

!/usr/bin/python# -- coding: UTF-8 -- >>> from functools import reduce>>> def fn(x, y):... return x * 10 + y...>>> def char2num(s):... digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}... return digits[s]...>>> reduce(fn, map(char2num, '13579'))13579

filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

Python内置的sorted()函数就可以对list进行排序:>>> sorted([36, 5, -12, 9, -21])[-21, -12, 5, 9, 36]sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:>>> sorted([36, 5, -12, 9, -21], key=abs)[5, 9, -12, -21, 36]>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)['about', 'bob', 'Credit', 'Zoo']要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True:>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)['Zoo', 'Credit', 'bob', 'about']

12.模块

Python 模块模块让你能够有逻辑地组织你的Python代码段。把相关的代码分配到一个 模块里能让你的代码更好用,更易懂。模块也是Python对象,具有随机的名字属性用来绑定或引用。简单地说,模块就是一个保存了Python代码的文件。模块能定义函数,类和变量。模块里也能包含可执行的代码。

例子:一个叫做aname的模块里的Python代码一般都能在一个叫aname.py的文件中找到。下例是个简单的模块support.py。def print_func( par ): print "Hello : ", par return

import 语句想使用Python源文件,只需在另一个源文件里执行import语句,语法如下:import module1[, module2[,... moduleN]

当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块support.py,需要把命令放在脚本的顶端

!/usr/bin/python3# -- coding: UTF-8 -- # 导入模块import support

现在可以调用模块里包含的函数了

support.print_func("Zara")

实例输出结果:Hello : Zara

From…import 语句Python的from语句让你从模块中导入一个指定的部分到当前命名空间中。语法如下:from modname import name1[, name2[, ... nameN]]例如,要导入模块fib的fibonacci函数,使用如下语句:from fib import fibonacci这个声明不会把整个fib模块导入到当前的命名空间中,它只会将fib里的fibonacci单个引入到执行这个声明的模块的全局符号表。

From…import* 语句把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:from modname import *这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。

dir()函数dir()函数一个排好序的字符串列表,内容是一个模块里定义过的名字。返回的列表容纳了在一个模块里定义的所有模块,变量和函数。如下一个简单的实例:

!/usr/bin/python# -- coding: UTF-8 -- # 导入内置math模块import math

content = dir(math)
print content;

['doc', 'file', 'name', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log','log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']

13.面向对象编程

Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。接下来我们先来简单的了解下面向对象的一些基本特征。

面向对象技术简介:

​ 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。实例变量:定义在方法中的变量,只作用于当前实例的类。继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。实例化:创建一个类的实例,类的具体对象。方法:类中定义的函数。对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

类的创建于实例化

使用class语句来创建一个新类,class之后为类的名称并以冒号结尾,类的帮助信息可以通过ClassName.__doc__查看。class_suite 由类成员,方法,数据属性组成。

!/usr/bin/python# -- coding: UTF-8 --

class Employee:

'所有员工的基类'

empCount = 0
def __init__(self, name, salary):      
	self.name = name      
	self.salary = salary      
	Employee.empCount += 1      
def displayCount(self):     
	print "Total Employee %d" % Employee.empCount   
def displayEmployee(self):      
print "Name : ", self.name,  ", Salary: ", self.salary

empCount变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用Employee.empCount访问。第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法

要创建一个类的实例,你可以使用类的名称,并通过__init__方法接受参数。

"创建 Employee 类的第一个对象"emp1 = Employee("Zara", 2000)"创建 Employee 类的第二个对象"emp2 = Employee("Manni", 5000)

访问属性您可以使用点(.)来访问对象的属性。使用如下类的名称访问类变量:

emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount

可以添加,删除,修改类的属性,如下所示:

emp1.age = 7 # 添加一个 'age'
属性emp1.age = 8 # 修改 'age' 属性
del emp1.age # 删除 'age' 属性

也可以使用以下函数的方式来访问属性

getattr(obj, name[, default]) : 访问对象的属性。
hasattr(obj,name) : 检查是否存在一个属性。
setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
delattr(obj, name) : 删除属性。
hasattr(emp1, 'age') # 如果存在 'age' 属性返回 True。
getattr(emp1, 'age') # 返回 'age' 属性的值
setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
delattr(empl, 'age') # 删除属性 'age'

Python内置类属性
dict : 类的属性(包含一个字典,由类的数据属性组成)
doc :类的文档字符串__name__: 类名
module: 类定义所在的模块(类的全名是'main.className',如果类位于一个导入模块mymod中,那么className.module 等于 mymod)
bases : 类的所有父类构成元素(包含了一个由所有父类组成的元组)

14.异常处理

异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。一般情况下,在Python无法正常处理程序时就会发生一个异常。异常是Python对象,表示一个错误。当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行。

捕捉异常可以使用try/except语句。
try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。如果你不想在异常发生时结束你的程序,只需在try里捕获它。语法:以下为简单的try....except...else的语法:

try:<语句>
      #运行别的代码
except <名字>:
	<语句>        
	#如果在try部份引发了'name'异常
except <名字>,<数据>:
	<语句>        
	#如果引发了'name'异常,获得附加的数据
else:<语句>       
	#如果没有异常发生

15.场景案例:

python的faker模块

在软件需求、开发、测试过程中,有时候需要使⽤⼀些测试数据,针对这种情况,我们⼀般要么使⽤已有的系统数据,要么需要⼿动制造⼀些数据。由于现在的业务系统数据多种多样,千变万化。在⼿动制造数据的过程中,可能需要花费⼤量精⼒和⼯作量,此项⼯作既繁复⼜容易出错,⽐如要构造⼀批⽤户三要素(姓名、⼿机号、⾝份证)、构造⼀批银⾏卡数据、或构造⼀批地址通讯录等。

Faker是什么Faker是⼀个Python包,主要⽤来创建伪数据,使⽤Faker包,⽆需再⼿动⽣成或者⼿写随机数来⽣成数据,只需要调⽤Faker提供的⽅法,即可完成数据的⽣成。

pyhon的faker模块比较简单,从faker模块倒入这个类,然后实例化这个类就可以使用了

from faker import Faker

faker=Faker()

name=faker.name()

address=faker.address()

print(name)

print(address)

输出信息

Ashely Love

074 Lee Suilt 644

faker常用模块举例:

faker模块 完整案例:

from faker import Faker
import xlwt
import random

faker = Faker("zh_CN")
gender = ["男", "女"]
education = ["小学", "初中", "高中", "大专", "大学本科", "研究生"]
asset = ["私人银行级:>800万元", "七星级:600~800万元", "六星级:100~600万元", "五星级:20~100万元",
"四星级:5~20万元", "三星级:1~20万元", "二星级:<1万元", "准星级:0"]
risk_tolerance = ["A1(保守型)", "A2(稳健型)", "A3(平衡型)", "A4(成长型)", "A5(进取型)"]

wb = xlwt.Workbook(encoding='utf-8')
sheet1 = wb.add_sheet('客户')
head_data = ['姓名', '性别', '年龄', '学历', '电话号', '资产等级', '风险承受能力等级']
for head in head_data:
sheet1.write(0, head_data.index(head), head)

for i in range(1, 100):
sheet1.write(i, 0, faker.name())
sheet1.write(i, 1, random.choice(gender))
sheet1.write(i, 2, random.randint(18, 70))
sheet1.write(i, 3, random.choice(education))
sheet1.write(i, 4, faker.phone_number())
sheet1.write(i, 5, random.choice(asset))
sheet1.write(i, 6, random.choice(risk_tolerance))
wb.save('客户.xls')

发表回复