一:数据驱动

file_operate.py文件

# coding=utf-8
"""@Project :pachong-master @File    :file_operate.py@Author  :gaojs@Date    :2022/7/1 23:00@Blogs   : https://www.gaojs.com.cn
"""
import openpyxl as xl
import yamldef read_excel(filepath, sheet_name):"""读取数据,将其转换成所需格式:return:"""# 得到整个excel文档对象wb = xl.load_workbook(filepath)# 获取某个sheet工作表数据sheet_data = wb[sheet_name]# 定义空列表,用来存储多行数据,每行数据都是一个列表data = []# 得到总行数lines_count = sheet_data.max_row# 得到总列数cols_count = sheet_data.max_columnfor li in range(2, lines_count+1):line = []for co in range(1, cols_count+1):cell = sheet_data.cell(li, co).valueif cell is None:cell = ''line.append(cell)data.append(line)return datadef write_excel(filepath, sheet_name, row, col, text):"""写入内容:return:"""wb = xl.load_workbook(filepath)sheet_data = wb[sheet_name]# 写入数据sheet_data.cell(row=row, column=col, value=text)wb.save(filepath)def read_yaml(filepath):"""读取yaml文件:return:"""with open(filepath, mode='r', encoding='utf-8') as fin:content = yaml.load(fin, Loader=yaml.FullLoader)return contentdef write_yaml(filepath, text):"""写入文件内容:return:"""with open(filepath, mode='w', encoding='utf-8') as fin:yaml.dump(text, fin, Dumper=yaml.Dumper)if __name__ == '__main__':# print(read_excel('./test_data.xlsx', '数据驱动数据'))# write_excel('./test_data.xlsx', '数据驱动数据', row=6, col=6, text='gaojianshuai')print(read_yaml('./test_data.yml').get('数据驱动数据'))write_yaml('./test_data1.yml', {'userName': 'gaojs', 'password': '1234'})

test_data.yml文件

# 数据驱动接口数据数据驱动数据:- ['admin', 1234, 200, 0, 'success']- ['', 1234, 200, 1, '参数为空']- ['admin', '', 200, 1, '参数为空']

二、pytest记录

conftest.py文件

# coding=utf-8
"""@Project :pachong-master @File    :conftest.py@Author  :gaojs@Date    :2022/6/30 21:47@Blogs   : https://www.gaojs.com.cn
"""
from typing import Listimport pytest
import requestsfrom 码同学.requests_study.cookie_study import login@pytest.fixture(scope='session', autouse=True)
def login_and_logout():print('在conftest.py中定义fixture,自动执行')login(userName='admin', password='1234')print('在档次执行测试中只执行一次,因为作用域是session')yieldprint('在当前执行测试只执行一次后置动作,因为作用域是session')# 重写pytest的一个hook函数,处理pycharm插件界面显示的执行结果乱码
def pytest_collection_modifyitems(items:List["item"]):for item in items:item.name = item.name.encode("utf-8").decode("unicode-escape")item._nodeid = item._nodeid.encode("utf-8").decode("unicode-escape")@pytest.fixture(scope='module', autouse=True)
def VPN0():print('在conftest.py中定义fixture,自动执行')login(userName='admin', password='1234')print('在当前每个用例执行一次,因为作用域是module')yieldprint('在当前每个用例执行后执行一次,因为作用域是module')

pytest.ini

不能有中文

[pytest]
addopts = -sv -n auto --dist=loadfiletestpaths = ./python_files = test*.pypython_classes = Test*python_functions = test_*

test_param_caresian.py

# coding=utf-8
"""@Project :pachong-master @File    :test_param_login.py@Author  :gaojs@Date    :2022/6/30 22:44@Blogs   : https://www.gaojs.com.cn
"""
import pytest
import requests# 第一步:将测试数据转换成python中列表套列表的格式
from 码同学.requests_study.cookie_study import login
from 码同学.requests_study.put_api_study import post_update_phone_info# 第二:使用pytest装饰器,将其传递给测试用例函数
brand = ['Apple', 'xiaomi', 'sanxing']
color = ['red', 'yellow', 'black']
memorySize = ['256G', '128G', '64G', '512G']
cpuCore=['8核', '4核', '16核']
expect_status_code = [200]
expect_code = ['0']
expect_message = ['更新成功']@pytest.mark.parametrize('brand', brand)
@pytest.mark.parametrize('color', color)
@pytest.mark.parametrize('memorySize', memorySize)
@pytest.mark.parametrize('cpuCore', cpuCore)
@pytest.mark.parametrize('expect_status_code', expect_status_code)
@pytest.mark.parametrize('expect_code', expect_code)
@pytest.mark.parametrize('expect_message', expect_message)
def test_put(brand, color, memorySize, cpuCore, expect_status_code, expect_code, expect_message):"""笛卡尔积参数化:return:"""resp = post_update_phone_info(brand=brand, color=color, memorySize=memorySize, cpuCore=cpuCore)status_code = resp.status_codeassert status_code == expect_status_code# 断言coderesp_json = resp.json()code = resp_json['code']assert code == expect_code# message断言result = resp_json['message']assert result == expect_message# 异常组合不适合笛卡尔积,只能对有效值多个值进行使用

test_param_login.py

# coding=utf-8
"""@Project :pachong-master @File    :test_param_login.py@Author  :gaojs@Date    :2022/6/30 22:44@Blogs   : https://www.gaojs.com.cn
"""
import pytest
import requests
from ..datadriver.file_operate import read_yaml, read_excel# 第一步:将测试数据转换成python中列表套列表的格式
from 码同学.requests_study.cookie_study import login# 第一种数据给定:指定在文件中
# test_data = [
#     ['admin', '1234', 200, '0', 'success'],
#     ['', '1234', 200, '1', '参数为空'],
#     ['admin', '', 200, '1', '参数为空']
# ]
# 第二种,通过调用file_operate文件中的方法读取excel数据
# test_data = read_excel(r'E:\爬虫\pachong-master\码同学\datadriver\test_data.xlsx', '数据驱动数据')
test_data = read_yaml(r'E:\爬虫\pachong-master\码同学\datadriver\test_data.yml').get('数据驱动数据')
print(test_data)@pytest.mark.parametrize('userName, password, expect_status_code, expect_code, expect_message', test_data)
def test_login_param(userName, password, expect_status_code, expect_code, expect_message):"""数据驱动:登录测试:return:"""resp = login(userName=userName, password=password)status_code = resp.status_codeassert status_code == expect_status_code# 断言coderesp_json = resp.json()code = resp_json['code']assert code == expect_code# message断言result = resp_json['message']assert result == expect_message

test_by_func.py

# coding=utf-8
"""@Project :pachong-master @File    :test_by_func.py@Author  :gaojs@Date    :2022/6/30 21:55@Blogs   : https://www.gaojs.com.cn
"""
# 以函数形式编写测试用例# 测试用例
from 码同学.requests_study.cookie_study import logindef test_login():"""登录测试用例:return:"""resp = login(userName='admin', password='1234')status_code = resp.status_codeassert status_code == 200# 业务断言,resp_json = resp.json()# print(resp_json)code = resp_json['code']assert code == '0'result = resp_json['message']assert result == 'success'def test_login_userisnull():"""登录测试用例:return:"""resp = login(userName='', password='1234')status_code = resp.status_codeassert status_code == 200# 业务断言,resp_json = resp.json()print(resp_json)code = resp_json['code']assert code == '1'result = resp_json['message']assert result == '参数为空'# 运行代码方式
"""
1.运行单个用例
pytest .\码同学\pytest_study\test_by_class.py::TestLogin::test_login_userisnull
2.运行整个类下 的所有用例
pytest -sv .\码同学\pytest_study\test_by_class.py
3.右键执行所有用例:光标放在所有第一个方法顶部4.右键执行某一个用例:贯标放在对应的函数上
"""

test_by_class.py

# coding=utf-8
"""@Project :pachong-master @File    :test_by_class.py@Author  :gaojs@Date    :2022/6/30 21:55@Blogs   : https://www.gaojs.com.cn
"""
# 以类形式编写测试用例# 测试用例
from 码同学.requests_study.cookie_study import loginclass TestLogin:# 测试用例1def test_login(self):"""登录测试用例:return:"""resp = login(userName='admin', password='1234')status_code = resp.status_codeassert status_code == 200# 业务断言,resp_json = resp.json()# print(resp_json)code = resp_json['code']assert code == '0'result = resp_json['message']assert result == 'success'# 测试用例2def test_login_userisnull(self):"""登录测试用例:return:"""resp = login(userName='', password='1234')status_code = resp.status_codeassert status_code == 200# 业务断言,resp_json = resp.json()print(resp_json)code = resp_json['code']assert code == '1'result = resp_json['message']assert result == '参数为空'# 运行代码方式
"""
1.运行单个用例
pytest .\码同学\pytest_study\test_by_class.py::TestLogin::test_login_userisnull
2.运行整个类下 的所有用例
pytest -sv .\码同学\pytest_study\test_by_class.py
3.右键执行所有用例
"""

test_preport_function.py

setup_function

# coding=utf-8
"""@Project :pachong-master @File    :test_prepost_module.py@Author  :gaojs@Date    :2022/6/30 22:18@Blogs   : https://www.gaojs.com.cn
"""
# 查询余额接口:首先登陆,然后查询,负责提示未登录from 码同学.requests_study.cookie_study import login, querydef setup_function():print('\n************setup_function:在当前脚本文件中,每个用例执行之前,都会执行一次登陆**************')# 登陆接口login(userName='admin', password='1234')def teardown_function():print('***********teardown_function: 在当前脚本文件中,每个测试用例执行后,都会执行一次**************')# 测试用例1:查询余额正确
def test_query():"""正常查询操作:return:"""resp = query(userName='admin')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '0'result = resp_json['message']assert result == 'success'# 测试用例2:错误的用户名
def test_query_error():"""正常查询操作:return:"""resp = query(userName='gaojs')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '1'result = resp_json['message']assert result == '用户未登录'

test_prepost_method.py

setup_method

# coding=utf-8
"""@Project :pachong-master @File    :test_prepost_module.py@Author  :gaojs@Date    :2022/6/30 22:18@Blogs   : https://www.gaojs.com.cn
"""
# 查询余额接口:首先登陆,然后查询,负责提示未登录
import pytestfrom 码同学.requests_study.cookie_study import login, queryclass TestQuery:def setup_method(self):print('\n************setup_method:在当前类中,每条测试用例执行之前,都会执行一次登陆**************')# 登陆接口login(userName='admin', password='1234')def teardown_method(self):print('***********teardown_method: 在当前类中,每条测试用例执行之后,都会执行一次**************')# 测试用例1:查询余额正确def test_query(self):"""正常查询操作:return:"""resp = query(userName='admin')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '0'pytest.assume(code == '0', f'实际值:{code},期望值是0')result = resp_json['message']# assert result == 'success'pytest.assume(result == 'success', f'实际值:{result},期望值是success')# 测试用例2:错误的用户名def test_query_error(self):"""正常查询操作:return:"""resp = query(userName='gaojs')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '1'result = resp_json['message']assert result == '用户未登录'

test_propost_module.py

setup_module

# coding=utf-8
"""@Project :pachong-master @File    :test_prepost_module.py@Author  :gaojs@Date    :2022/6/30 22:18@Blogs   : https://www.gaojs.com.cn
"""
# 查询余额接口:首先登陆,然后查询,负责提示未登录from 码同学.requests_study.cookie_study import login, querydef setup_module():print('\n************setup:在当前脚本文件中,所有执测试执行前,只执行一次登陆**************')# 登陆接口login(userName='admin', password='1234')def teardown_module():print('***********teardown: 在当前脚本文件中,所有执测试执行后,只执行一次**************')# 测试用例1:查询余额正确
def test_query():"""正常查询操作:return:"""resp = query(userName='admin')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '0'result = resp_json['message']assert result == 'success'# 测试用例2:错误的用户名
def test_query_error():"""正常查询操作:return:"""resp = query(userName='gaojs')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '1'result = resp_json['message']assert result == '用户未登录'

test_prepost_class.py

# coding=utf-8
"""@Project :pachong-master @File    :test_prepost_module.py@Author  :gaojs@Date    :2022/6/30 22:18@Blogs   : https://www.gaojs.com.cn
"""
# 查询余额接口:首先登陆,然后查询,负责提示未登录
import pytestfrom 码同学.requests_study.cookie_study import login, query# @pytest.fixture(scope='class', autouse=True)
# def login_and_logout():
#     print('\n************setup_class:在当前类中,在每个类执行之前,都会执行一次登陆**************')
#     login()
#     yield
#     print('***********teardown_class: 在当前类中,在每个类执行之后,都会执行一次**************')class TestQuery:# def setup_class(self):#     print('\n************setup_class:在当前类中,在每个类执行之前,都会执行一次登陆**************')#     # 登陆接口#     login(userName='admin', password='1234')## def teardown_class(self):#     print('***********teardown_class: 在当前类中,在每个类执行之后,都会执行一次**************')# 测试用例1:查询余额正确def test_query(self, login_and_logout):"""正常查询操作:return:"""resp = query(userName='admin')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '0'result = resp_json['message']assert result == 'success'# 测试用例2:错误的用户名def test_query_error(self, login_and_logout):"""正常查询操作:return:"""resp = query(userName='gaojs')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '1'result = resp_json['message']assert result == '用户未登录'class TestQuery1:# 测试用例1:查询余额正确def test_query1(self, login_and_logout):"""正常查询操作:return:"""resp = query(userName='admin')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '0'result = resp_json['message']assert result == 'success'# 测试用例2:错误的用户名def test_query_error1(self, login_and_logout):"""正常查询操作:return:"""resp = query(userName='gaojs')status = resp.status_codeassert status == 200resp_json = resp.json()code = resp_json['code']assert code == '1'result = resp_json['message']assert result == '用户未登录'

readME文件

总结:
1.模块级别最大,因为不管是函数式测试用例,还是类方式的测试用例,都在一个模块中
2.函数级别仅仅是针对,函数式测试用例生效(setup_function()不能再类方式中使用,类方式中要使用setup_method())
3.类级别和方法级别,是针对于类方式编写的测试用例生效
4.setup和teardown是可以替换函数级别和方法级别的前置后置1.运行单个用例
pytest .\码同学\pytest_study\test_by_class.py::TestLogin::test_login_userisnull
2.运行整个类下 的所有用例
pytest -sv .\码同学\pytest_study\test_by_class.py
3.右键执行所有用例:光标放在所有第一个方法顶部4.右键执行某一个用例:贯标放在对应的函数上异常组合不适合笛卡尔积,只能对有效值多个值进行使用

三、requests记录

cookie_study.py

# coding=utf-8
"""@Project :pachong-master @File    :cookie_study.py@Author  :gaojs@Date    :2022/6/28 22:50@Blogs   : https://www.gaojs.com.cn
"""
import requests# 多个接口使用同一个session对象的话,他会自动的帮我们去管理和关联cookie
session = requests.session()def login(userName='admin', password='1234'):"""登录操作:return:"""url = 'http://localhost:9090/bank/api/login'data = {'userName': userName,'password': password}rsp = session.post(url=url, data=data)result = rsp.json().get('message')return rspdef query(userName='admin'):"""银行余额查询接口:return:"""url = 'http://localhost:9090/bank/api/query'params = {'userName': userName}rsp = session.get(url=url, params=params)print(rsp.text)result = rsp.json().get('message')print(result)money_data = rsp.json().get('data')print(money_data)return rsplogin()
query()

delete_api.py

# coding=utf-8
"""@Project :pachong-master @File    :delete_api_study.py@Author  :gaojs@Date    :2022/6/28 23:26@Blogs   : https://www.gaojs.com.cn
"""
import requestsdef delete_phone_info():"""put请求更新手机信息:return:"""url = 'http://localhost:9090/com/phone'data = {"brand": "Apple", "color": "red","memorySize": "256G", "cpuCore": "8核","price": "10080", "desc": "全新上市"}rsp = requests.delete(url=url, json=data)print(rsp.text)result = rsp.json().get('message')print(result)

file_upload.py

# coding=utf-8
"""@Project :pachong-master @File    :file_upload_study.py@Author  :gaojs@Date    :2022/6/28 23:17@Blogs   : https://www.gaojs.com.cn
"""
import requestssession = requests.session()def file_upload():"""上传文件:return:"""url = 'http://localhost:9090/file/api/upload2'file = {'file': open(r'C:\Users\Administrator\Desktop\123.jpg', mode='rb')}rsp = session.post(url=url, files=file)result = rsp.json().get('message')print(result)if __name__ == '__main__':file_upload()

post_api.py

# coding=utf-8
"""@Project :pachong-master @File    :post_api_study.py@Author  :gaojs@Date    :2022/6/28 22:43@Blogs   : https://www.gaojs.com.cn
"""
import requestsdef post_api():"""post请求:return:"""url = 'http://localhost:9090/com/login'data = {'userName': 'admin','password': '1234'}rsp = requests.post(url=url, data=data)result = rsp.json().get('message')print(result)def post_add_phone_info():"""新增手机信息:return:"""url = 'http://localhost:9090/com/phone'data = {"brand": "Huawei", "color": "yellow","memorySize": "64G", "cpuCore": "8核","price": "8848", "desc": "全新上市"}rsp = requests.post(url=url, json=data)result = rsp.json().get('message')print(result)

put_api.py

# coding=utf-8
"""@Project :pachong-master @File    :put_api_study.py@Author  :gaojs@Date    :2022/6/28 22:49@Blogs   : https://www.gaojs.com.cn
"""
import requestsdef post_update_phone_info(brand='Apple', color='red', memorySize='256G', cpuCore='8核'):"""put请求更新手机信息:return:"""url = 'http://localhost:9090/com/phone'data = {"brand": brand,"color": color,"memorySize": memorySize,"cpuCore": cpuCore,"price": "10080","desc": "全新上市"}rsp = requests.put(url=url, json=data)result = rsp.json().get('message')print(result)return rsppost_update_phone_info()

token_study.py

# coding=utf-8
"""@Project :pachong-master @File    :token_study.py@Author  :gaojs@Date    :2022/6/28 23:01@Blogs   : https://www.gaojs.com.cn
"""
import requestssession = requests.session()def login(userName='admin', password='1234'):"""获取token:return:"""url = 'http://localhost:9090/bank/api/login2'data = {'userName': userName,'password': password}rsp = session.post(url=url, data=data)print(rsp.text)return rspdef post_api_token(userName='admin', password='1234'):"""获取token:return:"""url = 'http://localhost:9090/bank/api/login2'data = {'userName': userName,'password': password}rsp = session.post(url=url, data=data)print(rsp.text)msg = rsp.json().get('message')print(msg)global tokentoken = rsp.json().get('data')print(token)return tokendef query_money():"""银行余额查询接口:return:"""url = 'http://localhost:9090/bank/api/query2'params = {'userName': 'admin'}headers = {'testfan-token': token}rsp = session.get(url=url, headers=headers, params=params)print(rsp.text)result = rsp.json().get('data')print(result)if __name__ == '__main__':post_api_token()query_money()

readME

总结:
requests库的请求方法参数众多,划分如下:global全局参数使用:不通的函数中如果想使用的话就用global查询参数就用params=params
表单参数就用data=data
json参数就用json=json
文件参数就用files=files
请求头信息headers就用headers=headers

pytest数据驱动及conftest文件及装饰器使用相关推荐

  1. 【单元测试】pytest:配置|断言|参数化|夹具|装饰器|插件

    [单元测试]pytest 入门案例 pytest配置文件 断言 参数化 夹具 模块级 类级 方法级 函数级 fixture装饰器 插件 unittest:python自带的单元测试框架,兼容性好 py ...

  2. python文件下载速度 装饰器_python学习笔记之---装饰器

    # -*- coding:utf-8 -*- '''示例1: 最简单的函数,表示调用了两次''' def myfunc(): print ("myfunc() called.") ...

  3. python文件下载速度 装饰器_python使用装饰器对文件进行读写操作'及遍历文件目录...

    '''使用装饰器对文件进行读写操作''' #def check_permission(func):#'''演示嵌套函数定义及使用'''#def wrapper(*args,**kwargs):#''' ...

  4. 【Pytest+Allure】pytest+allure自学轨迹1--认识pytest和pytest的装饰器

    认识pytest和pytest的装饰器 认识pytest pytest的装饰器 使用pytest 安装与导入 pytest用例的写法 使用fixture装饰器 作用域 不指定作用域(默认作用域func ...

  5. Python pytest框架之@pytest.fixture()和conftest详解

    一.fixture简介 学pytest就不得不说fixture,fixture是pytest的精髓所在,类似unittest中setup/teardown这种前后置东西.但是比它们要强大.灵活很多,它 ...

  6. Python装饰器学习笔记

    Python装饰器 文章目录 Python装饰器 基本概念 从零开始的逐步分析 修饰后的问题 向被包装后的函数传递参数 使用场景:stdout日志 接受参数的装饰器 作为一个类的装饰器 总结 学习资料 ...

  7. 装饰器python3菜鸟教程_认识Python装饰器

    Python中的装饰器用来给Python中的函数添加一些辅助功能.比如我们可以把[输出日志]这个辅助功能写到一个装饰器里.只要我们在某个函数A之前添加了这个[输出日志]的装饰器,那么执行函数A的时候, ...

  8. 软件测试 pytest pytest的命名规则 用例的前后置 conftest.py 定制allure报告 @pytest.mark.parametrize()装饰器作数据驱动

    文章目录 1 pytest简介 1.1 pytest的命名规则 1.2 运行方式 1.2.1 主函数方式(少用) 1.2.2 命令行方式(少用) 1.2.3 pytest.ini的配置文件方式(最经常 ...

  9. Python Pytest装饰器@pytest.mark.parametrize用例数据驱动(三)

    一.测试用例用excel管理,存放地址:C:\Users\wangli\PycharmProjects\Test\test\files\apiCase.xls 二.代码实现如下: 1.封装读取exce ...

最新文章

  1. android wear无法启用,android-wear – 无法创建Android虚拟设备,“没有为此目标安装系统映像”...
  2. Appium环境安装
  3. TensorFlow Serving + Docker + Tornado机器学习模型生产级快速部署
  4. list赋值给另一个list_Python小知识: List的赋值方法,不能直接等于
  5. STC单片机程序下载失败总结
  6. C#利用SQLDMO备份与还原数据库
  7. 幼儿园小班上计算机课 作业内容是手口一致,小班幼儿手口不能一致的点数怎么办...
  8. python中字典按键或键值排序_[宜配屋]听图阁
  9. xlsx文件打开乱码_excel表格文件打开都是乱码怎么解决
  10. 【通信协议学习】关于Xmodem、Ymodem、Zmodem、ASCII、Binary传输协议
  11. java如何统计txt的字数_Java HashSet对txt文本内容去重(统计小说用过的字或字数)...
  12. 信号调制三种方法的带宽比较
  13. c语言错误1083,没有混音设备可用,启动Windows Audio服务时错误1083
  14. 【FICO】标准成本、计划成本、实际成本、目标成本
  15. 生活在深圳我们需要的不是叹息与感概
  16. 用于传感器互操作性问题的指纹匹配系统的大规模研究
  17. Canvas如何等待所有图片加载完成才开始绘图
  18. java按键发出声音代码_用Java写的一个根据按键发声的程序,为什么只有前16次按键响...
  19. “大数据杀熟”谁之祸?
  20. 记忆存储程序使得计算机能够实现,2016年职称计算机考试模块综合试题及答案(4)...

热门文章

  1. 什么是:VGA SVGA XGA SXGA
  2. 一个计算机几个用户登录,一台电脑登录多个头条账号的方法,用这个软件很方便!...
  3. 帮G1刷新的hboot和radio
  4. win7安装Microsoft Visial C++2015 Redistributable提示:无法建立到信任根
  5. linux如何运行windows游戏,cedega - Ubuntu下也玩Windows游戏,三种途径开启魔兽[图文]_Linux教程_Linux公社-Linux系统门户网站...
  6. 前端简介,head内标签
  7. WireShark 简介
  8. 无公网IP?教你在外远程访问本地wamp服务器「内网穿透」
  9. Matlab学习-CDF(累积分布函数图)绘制
  10. EasyX的下载与使用教程网址