1、你做了几年的测试、自动化测试,说一下 selenium 的原理是什么?
我做了五年的测试,1年的自动化测试;
selenium 它是用 http 协议来连接 webdriver ,客户端可以使用 Java 或者 Python 各种编程语言来实现;
2、什么项目适合做自动化测试?
关键字:不变的、重复的、规范的
第一点,需求变化不能太频繁;
第二点,项目周期要足够长,如果自动化代码还没有写完,公司就倒闭了,那也不需要自动化了
第三点,脚本可以重复使用:在一些典型的场景,比如说 “冒烟测试、回归测试” 的地方就是经常使用自动化测试;
第四点,被测试的软件是否规范:比如说是不是有需求文档、规范的接口文档、是否有原型图、你的接口设计是不是比较规范;
第五点,手工测试是无法完成的;比如说一个性能测试,不能同时有 一千只手一直做好点点点,自动化测试的成本不是特别高
3、Python 生成器 和迭代器的区别?
作为迭代器必须实现两个特定的方法 “iter(),next()” ;
生成器是一种特许的迭代器,支持所有的迭代操作,除此之外生成器还实现了,普通迭代器没有的一些特性;
比如说它可以通过 send 的方法与生成器内部进行数据交互;还有它可以通过 close 方法去进行关闭;甚至还可以通过 throw 方法,引发内部的异常;
4、为什么用 Mac 写代码?
表面原因是 Mac 方便易用,颜值也高;深层原因是因为现在的服务器,大多都是采用 Linux 系统,而 Mac 系统 和 Linux 系统其实都是基于原来的 Unix 系统开发的;
而 Mac 基本上能够维持我们的开发环境和线上的一致性;
为什么不用 Linux ?
用 Linux 写代码也是一个很好的选择,但是 Linux 的界面操作和他的娱乐功能不是特别强,而 Mac 做到了很好的平衡;
5、你是怎么开展自动化测试工作的?
第一,根据产品的业务特性整理出来,可以做自动化的一个功能模板;
第二,我们会根据有限级以及人员现状,来制定自动化测试计划;
第三,我们会从功能用例当中挑选合适的用例来转成自动化用例;
第四,是框架选型,选择编制语言或者工具来实现,我们的团队都是会代码的能力还不错,所以我们选择的是 Python 语言来实现的;
第五,就是自动化测试的脚本开发;
第六,根据项目来制定自动化的执行方案;
第七,就是测试报告的分析工作,以及 自动化测试成果的汇报,跟进后期的维护;
6、请说下什么是闭包函数?
完成的闭包必须包含以下三个特性:函数中必须嵌套一个函数;外层函数返回值是内层函数的函数名;内存嵌套函数对外层作用率,有非全局变量的引用;
简单来说闭包函数,第二个返回的不仅仅是一个简单的函数,这个函数它还呆了一个封闭的作用域;
7、请介绍一下你的自动化测试框架?
在上家公司搭建了 API 接口自动化测试框架,使用 Python 中的 unittest 框架结合 requests 模块,采用数据驱动思想(ddt)和分层设计理念,实现测试用例自动化执行;
我的框架主要分为一下几大模块:
模块一:cases(K色死)文件夹,自己根据接口需求封装的模块(注册,登录,充值),保存测试用例的类
模块二:configs(康菲格斯)文件夹,配置文件,存放项目当中共有配置:文件名、日志器,数据库,url地址
模块三:datas(得塔斯):保存测试用例 Excel 文档数据;
往往一条测试用例的自动化代码都是一样的,只不过只是数据不同而已,会将数据和代码分离,使用 ddt 进行驱动,这分离就是数据驱动思想;
会将一条测试用例的数据放到 Excel 、数据库中,一条数据代表一条用例,这样可以精简代码,方便维护
模块四:libs(来波斯)文件夹,第三方库文件夹、ddt 和 HTML 报告;
ddt:修改 ddt 库,如果数据是字典,则获取字典当中的 title 对应的值,加到测试用例名称中;HTML 报告,使用更加美化详细的报告
模块五:logs(老格斯)文件夹,存放日志文件;
模块六:reports(瑞跑次)文件夹,存放生成的报告
模块七:scripts(思怪珀斯)文件夹,存放封装的类和模块,封装了通用的工具模块
constants :(康斯ten死)py文件是存储目录路径文件;使用 os 库,存放定位的文件目录 import os
handle_config.py:(憨豆个.康飞个)文件封装了对配置文件的读写操作;
from configparser import ConfigParser 使用 (康飞个.拍儿涩)方法,进行配置文件的读写
handle_context.py:(憨豆.康 泰可斯特)py文件是参数化的封装;
使用 re 模块,正则来实现参数化 search (译:涩吃)方法搜索、sub(译:萨博)方法替换操作
handle_excel.py:(憨豆.一颗赛欧)py 文件是 对Excel 文件的封装;
使用 openpyxl 模块,来处理 excel 文件对,文件进行读写操作, 存储测试数据(用例数据)用例数据);包括:获取所有测试用例、对执行结果在指定行进行写入
第一步. 打开excel文件:使用load_workbook(译:楼的我的不可)传入文件名,默认active 获取第一个表单,否则获取指定的表单
获取表头的信息,使用iter_rows(艾特木肉丝)方法,嵌套元祖的元祖,省略最小行号
zip函数将表头的元祖与每一行用例所在的元祖进行拼接,dict转换为字典后,添加到列表当中one_list = []
handle_log.py:(憨豆.啷个)py文件是,使用 logging (啷个应)模块,来创建日志器, 记录项目中的日志信息;import logging
1. 定义日志收集器,使用.getLogger方法,收集器的名字case
2. 指定日志收集器的日志等级,使用logging对象中.setLevel方法(赛特。莱欧)
3. 定义日志输出渠道
输出到控制台,使用logging(老根)当中的.StreamHandler(丝锥木汗都)
输出到文件,使用logging(老根)当中的.FileHandler(发偶。憨豆)方法,(指定文件名, 默认a以追加的方式,)
4. 指定日志输出渠道的日志等级,使用对象.setLevel(赛特。莱欧)方法
5. 定义日志显示的格式,logging(老根)当中的 Formatter(佛梅特) 函数
6. 对接, 将日志收集器与输出渠道对接,收集器中addHandler(按得,憨豆)函数
handle_mysql.py:(憨豆.满色口)py文件是 MySQL 数据库封装;
使用 pymysql 库来连接 mysql 数据库,进行数据库操作的封装;主要是执行sql语句, 进行数据校验;import pymysql
import random (译:软的木),Python中的 random 模块用于生成随机数
1.建立链接,使用 pymysql 库中的 connect(可耐科特)
2.创建游标 cursor(烤色)
3.需要执行 sql 语句
4.执行那条 sql 语句,使用 游标 当中的 execute(埃克斯Q特)
5.手动提交,使用 链接对象当中的 commit(可买次)
6.获取执行结果,使用 游标 当中的 fetchone(翻吃万)
7.关闭链接,释放资源 close(科楼司)
先关游标 cursor.close()
再关闭游标对象 conn.close()
handle_request.py:(憨豆.瑞快死特)py文件是 requests 请求库的封装;
使用 requests (瑞快死特)库用来向接口发起请求的封装;import requests
handle_user.py:(憨豆。有责儿)py文件是
使用 上面封装的:数据库操作,requests 接口请求封装、配置文件封装类、来创建 一个用户
run.py:入口文件,收集并执行测试用来
自动识别加载测试用例的方法:discover (译:迪斯卡瓦)方法
先加载测试用例
使用 unittest 中 defaultTestLoader(译:滴fao的.泰斯特.楼泽)中 discover(迪斯卡瓦)方法
第一种,使用 . 代表当前py文件所在的路径,自动加载以 test 开头的 py 文件模块
第二种,使用绝对路径加载,使用 r 进行转码
执行用例
1.需要创建执行器对象,使用 unittest 当中的 TextTestRunner(译:泰斯特.泰斯特.软那儿)
one_runner = unittest.TextTestRunner()
2.运行套件
one_runner.run(one_suite)
能够 web 自动化测试框架,采用 PO 模式和关键字驱动思想,使用 Python 中的 pytest 框架结合 selenium 模块和 allure 插件,实现测试用例自动化执行
8、pytest 和 unittest 的区别?
首先 unittest 是 pytest 官方库,兼容性更好更稳定,pytest 在安装的时候可能会出现和 Python 的版本出现兼容问题;
在 用例编写上面,unittest 当中,用例都是以类的形式编写的,并且都要继承于这个 testcase;
pytest 当中,支持函数 和 类两种形式,并且 pytest 有 conftest.py 这个文件来支持全局的共享前置后置;
在 用例收集上, unittest 当中,要利用 testloader he testsuite 来主动收集和加载用例;pytest 当中,能够自动识别用例;
在 用例分类和筛选上面,unittest 当中,对现有的用例进行一个筛选和处理的话是比较麻烦的;pytest 当中,可以通过打标记来轻松实现用例筛选;
在 运行失败的机制上面,unittest 当中,官方库并没有提供失败重启的机制;pytest 当中,自带的失败重运行机制;
在 运行过程上面,unittest 当中,没有支持的插件;pytest 当中,有 700 多个插件,可以支持的插件非常丰富;
9、列表推导式是什么?
推导式 是 Python 中用来生成数据的一种高级用法,Python 不仅有列表推导时,还有字典推导式、集合推导式、生成器表达式;
它的语法都是一样的,都是通过 for 循环来创建数据的一种简写的方式;
10、什么是 PO 模式?
PO模式:全称:Page Object Model (译:配只.奥播摘可t.毛豆)简称POM,叫做页面对象,针对页面、UI界面;
PO 思想主要来源于 马丁福勒(marktin Flowwer)在 2004年发表的一篇文章最开始他不叫 PO ,而是叫做 window driver ,后来 selenium 沿用了这种思想,所以改成了 PO;
主要用途:是把一个具体的页面转化为编程语言当中的一个对象,页面特性转化成对象属性,页面操作转化为对象方法;
在自动化测试当中,主要用来实现对页面操作和测试逻辑的一个分离;
11、最熟悉的 selenium 操作?
基本上 selenium 提供的一下几大类操作都能够灵活使用,比如说:八大元素定位方式、三大等待方式、用户点击、输入等常见操作、
还有窗口切换、iframe 切换操作,比如说 actionchains 文件上传、JS操作 等一些复杂问题的操作;
对于 selenium 还没有提供现场封装方法的话 会查阅 W3C 组织提供的 webdriver 标准进行自己进行捕捉;
12、selenium 中登录按钮除了 click 还有什么方式?
还有这两种方式:比如说要用到 物理键盘进行操作,发出回车指令;然后,如果说这个登录按钮,在一个表单里面的话,也可以在定位到这个用户输入框,输入完了之后,直接用3D 方法进行提交
13、PO 模式的封装原则有哪些?
selenium 在官方的 wiki 上面给我们提供了六个原则,实际测试过程中可以这么理解:
第一个原则是,公共方法表示页面提供的一个服务,比如我们可以把 登录封装成一个 logo 的方法,把搜索方法封装成一个设施方法,把注册操作封装成一个 register 的方法;
第二个原则是,尽量不要暴露页面的内部;比如说一个HTML的页面还有一个页面的上下结构;
第三个原则是,在 PO 当中一般不做断言,会做到页面逻辑和测试逻辑的分离
第四个原则是,PO 一般里面的方法返回 self 或者是其他的 Page Object 也可以是一个元素属性
第五个原则是,整个 PO 你不需要封装整个页面的行为,用到什么逻辑就封装什么
第六个原则是,对于统一操作,如果出现不同的结果,可以把用不同的方法来表示,比如说登录成功有跳转,登录失败有报错,
如果登录还有一种会授权的状况,那么可以封装成三个单独的方法:login success、login error、login invalid
14、Python 中的小整数池你有了解过吗?
小整数池 是指在运行 Python 程序的时候,Python 解释器会自动创建,负 5 到 256 之间的整数对象,保存到缓存里面,也就是我们所说的小整数池;
当程序中将这些整数复制给变量的时候,那么 Python 解释器,就会不断重新去分配内存去创建这个对象了,而是直接引用,已经创建好的缓存里面的对象;
小整数池这个设计的初衷是为了优化程序的运行效率,需要相同的整数的时候,直接从这个整数池里面拿出来就可以用,可以避免频繁去创建和销毁这个对象,提升效率、节约内存;
15、Xpath 和 CSS 选择器有什么区别?
CSS 的写法会简单一点,xpath 会相对复杂一些,在主流浏览器中,CSS 的解析的效率更高一点,查找的速度会更快;
Xpath 支持的函数更多,操作的方式灵活功能会强大一点,对于复杂的元素定位,xpath 反而会更加简洁;
CSS 它不支持 文本定位;Xpath 是支持文本定位的;
16、需要鉴权的接口,你是如何处理的?
首先,确认一下接口是采用什么方式进行的鉴权的,是 cookie_session 还是 token ;
如果是 cookie_ session 的方式,那么可以直接用 requests 模块里面的 session 类去创建一个对象直接发送请求,它会自动记录 cookie 信息;
如果是 token ,那么先分析 token 是怎么返回的,然后提取对应的 token 的值,在发送请求的时候需要根据需求传入这个 token ;
17、UI 自动化中常用的等待方式?
UI 自动化测试当中等待的方式 主要有三种:
第一种,强制等待,一般情况下我们不太使用;他主要用的场景在于不同系统交互的地方;
第二种,隐式等待:这种等待比较智能,它可以通过全局配置,但是智能用于元素定位;
第三种,显示等待:是 selenium 当中比较灵活的一种等待方式;他的实现原理,其实是通过 while 循环不停的尝试需要进行的操作;
19、find_element() 和 find_elements() 有什么区别?
find_element() :返回找到的第一元素,如果找不到的话会直接报错;
find_elements() :会返回所有符合条件的元素,放到一个列表里面;如果找不到的话也不会报错,返回的是一个空列表;
20、什么是 XPATH ?
Xpath 是 XML 路径语言(XML Path Language),可以用来查询各个网页当中的元素位置,我们在自动化测试过程中呢,可以对 网页 和 APP 页面的元素进行精准定位
然后在爬虫领域可以对页面结构进行灵活的解析
21、request 模块发送请求的时候,怎么传递参数?
首先要确认一下接口的请求参数是什么类型的,如果接口需要的是查询字符串参数的话,那么就是 params 查;如果接口需要的是 json 型的参数的话,那么就直接使用 json 去查;
如果是 上传文件 的情况的话,那么可以通过 files 的参数来传递;
如果是 表单类型 的情况的话,那么可以使用 data 来传递,data 默认就是用来传递表单类型的参数;
那么当使用 data 传参的时候,也可以在那个请求头中,通过 content type 来指定这个请求参数的类型
22、selenium 自动化如何进行文件上传?
如果是 input 元素的文件上传,可以通过 selenium 当中的 send_keys 方式进行传递,但是这种方式局限性比较大,如果遇到像通过 js 调用的组件呢,会有一些问题;
这个时候就需要通过一些和系统交互的方式去完成上传操作,比如通过 autoit,pywinauto 或者是 pyautogui 这些第三方库进行操作
23、列表反转的几种方式?
第一种,是可以通过倒序切片反转,然后步长是 -1,;
第二种,是可以通过 列表的方式,列表有一个方法叫做 reverse (译:瑞外儿四),可以实现反转;
24、Python 中的类方法、实例方法、静态方法 有何区别?
类方法就是 类的方法,在定义的时候需要在上方加上一个 @classmethod 进行修饰,形参是 cls;类 和 实例 都是可以去调用;
实例方法是 实例对象方法,只有实例对象可以调用,类是不能调用的,形参是 self 指的是对象本身;
静态方法是一个任意的函数,只是刚好放在这个类里面,他需要在上方加上一个 @staticmethod 进行修饰,可以使用对象直接调用;,静态方法跟这个类没有太大的关系;
25、Python 当中的装饰器是什么?
装饰器 又叫 修饰器,是Python 中的高阶语法,装饰器可以通过 类 或者 函数 来实现,通常使用 @ 符号来表示一个装饰器;
作用:是用来扩展投个 函数 或者 类 的功能
26、Python 中的深复制 和 浅复制有什么区别?
深浅复制 通常是在数据嵌套的情况下讨论,当被嵌套的数据是 可变类型 的数据的情况下,对这个数据进行复制的时候,我们就要考虑到这个深浅复制;
浅复制,比如说,列表嵌套列表,列表中自带的 copy 方法进行复制就是 浅复制;
调用 copy 方法复制列表的时候,只会复制这个列表,列表中引用的其他数据(比如嵌套的列表)不会进行复制,是直接引用;
浅复制由于复制的不彻底,原列表引用的数据发送变化的时候,那么复制之后的数据也会受到影响
深复制,就要用到 copy 模块里面的 deepcopy 方法,调用 deepcopy 方法复制列表的时候,不仅会复制这个列表,而列表中引用的其他数据(比如嵌套列表)也会进行复制;
27、什么是 PEP8 规范?
PEP8规范 又叫 Python8号增强提案,他主要针对于 Python 代码编写风格,而制定的一个指南;
比如:首先在一个模块中,模块中的函数 或者 类,他们的间隔是两行;然后类里面的方法,他们间隔是一行;代码行的缩进通常用一个 tab 键 及四个空格来表示;
然后一行代码 PEP8的规范里面指出来,最大应该是79个字符;
关于这个规范还有很多要求,也就不一一举例了;
28、Python 函数的重载机制是什么?
函数重载主要是为了解决两个问题:第一个,是可变参数类型,第二个,是可变参数个数;
在 Python 当中参数不需要申明类型,函数是可以接受任何类型的参数的;如果函数的功能相同,一个函数就可以处理了;
在 Python 当中通过 一个 * 号 和 两个 ** 号 来处理可变参数个数;所以在 Python 里面他不需要处理函数重载;
29、Python 中常见的 可变参数类型 和 不可变参数类型 都有哪些?
不可变的数据类型包括:整数、浮点数、负数、布尔值、字符串
可变参数类型包括:字典、列表、集合、元祖
30、你的项目是什么阶段介入接口自动化测试的?
首先,我这个项目是一个全新的项目,我负责接口测试,另外五个人负责功能测试;因为是新项目,所以我在项目开发阶段,我就开始介入接口自动化;
编写了自动化用例,我们使用 yapi 平台管理接口的,相当于是提供了接口文档,由于介入的时间比较早,在这个过程当中,自动化发现了 几百个 bug;
为了后面的功能测试人员节约了很多时间,同时也能够保证,跟的上频繁上线的步伐;
31、关于 Python 中的 intern 机制,你有了解过吗?
在运行 Python 程序的时候,会专门分配一块空白的内存空间,用来保存由数字、字母、下划线组成的字符串,也就是纯单词、字符组成的字符串,
这块空白的内存就被称为 字符串驻留池,也称作 大整数池;
所谓的 intern 机制,就是在程序运行过程中创建新的字符串的时候,首先根据这个字符串,驻留池里面查找是否这个字符串,在这个驻留池里面是否已经创建了;
如果有的话就已经直接拿过来用,如果没有的话就在重新创建;创建之后如果是一个纯单词字符的话,会加入到这个驻留池当中,这样的一个机制,能够避免频繁的创建和销毁;
这个对象能够提升我们程序的一个运行效率;
32、Python 中 *args 和 **kwargs 的作用?
都是不定长,可以解决函数中参数不固定的问题,*args 可以把位置参数转化成元祖;**kwargs 可以把 关键字参数转化成字典;
33、进程,线程,协成,你是怎么理解的?
进程是操作系统资源分配的基本单位;线程是操作系统调度的基本单位;协成 也叫 微线程,协成 存在于线程 之中,是比线程更小的可执行单元;
进程和线程可根据操作系统的调度,有可能是并发执行,有可能是并行;协成在一个线程之中,只能并发不能实现并行
34、Python 的多线程有什么缺点?
根据 Python 官方文档知道,由于 Cpython 解释器的全局解释器锁的存在,那么多线程在同一时刻只能有一个线程执行,
意思就是说 Python 中的多线程只能并发执行,没有办法实现真正的并行;也就是无法利用多核 CPU 的资源
35、Python 如何去操作 MySQL 数据库?
可以使用的库有几个:pymysql、或者是 mysql_clinet 都可以进行连接;建立游标对象以后就可以直接执行 SQL 语句了
36、Python 总什么是 命名元祖?
命名元祖 是 Python 提供的一个叫做 namedtuple 的类,可以从 collection 包中导入,命名元组继承自 元祖类,所以具备元组的特性,
同时他可以访问属性的方式去获取,元组的元素可读性大大的提高,也可以非常方便的转换成像字典这样类型;
37、函数的参数定义有几种方式?
必传参数、默认参数、可变长参数
38、类里面去定义方法有几种形式?
分别是 实例方法、静态方法、类方法
类方法 和 实例方法 它都是跟类 或者 实例 有关系,它们的参数总是一个 实例 或者 类
但是 静态方法 就是一个普通函数,只不过我们刚好把他扔到了这个类的里面而已,它的参数没有说一定要是 类 或是谁;
39、unittest 框架的几个概念,几个组件?
一共有五个概念:
TestCase :是用来编写测试用例的,我们所编写的所有测试用例都需要继承 testcase 这个类;
TestSuite :是用来加载测试用例的容器,也就是一个测试套件,
TesttLoader :是用来收集测试用例的,并加载到这个测试套件里面的;
TestTestRunner :是用来运行测试用例,并生成文本形式的报告的;我们可以换成 HtmlTestRunner 来生成 HTML 格式的报告;
fixture :是就是夹具,用例或者 用例的前置和后置工作可以在这个里面做
40、Python 中的魔术方法了解过吗?
有了解过,Python 类当中内置的那个双下划 开头 和 结尾 的方法,都叫做 魔法函数,它是在特定的情况下除法的;
比如说:类的初始化 init,它就是在创建对象的时候会自动调用,用于初始化对象;
Python 当中有很多的特性,都是通过魔术方法来实现的,
41、Python 中如何定义匿名函数?
Python 中定义匿名函数非常简单,通过 lambda 表达式来定义就可以了;
lambda 表达式的基本句法是:lambda 空格 然后加上函数的参数,接下来在冒号后面跟上函数的返回值;
42、Python 中 queue 模块队列 和 进程 queue 队列,有什么区别?
queue 模块中的 Queue 只能在同一个进程中进行通信,只能实现多线程的数据交互,不能实现多进程的数据交互;
那么 进程 模块当中的 Queue 可以跨进程使用,能够实现多进程进行数据交互,
43、同步请求 和 异步请求 的区别?
同步请求,是指在一个线程当中,如果你发起一次请求以后,在收到返回结果之前,你是不能发起下一次请求的;
异步请求,是指在 同一个线程当中,如果你发起一次请求以后,在等待返回结果的这段时间之内,你可以继续去发起其他的请求
44、Python 中 with 操作文件为什么不用手动关闭,原理是什么?
Python 中的 with 关键字,它是用来启动一个对象的上下文管理器的;
他的原理是:当我们使用 with 去通过 open 打开文件的时候,它会触发文件对象的上下文管理器,然后当 with 当中的代码运行结束后,会自动去调用上下文管理器的退出方法;
在这个方法中他会去调用 close 来关闭文件,所以不需要我们手动去关闭文件;
45、Python 中的垃圾回收机制是什么?
我们常用的Python 解释器 CPython 主要使用了三种垃圾回收机制来完成对这个无效数据的回收以及内存的释放,分别是:引用计数、标记清除 还有 分代回收
垃圾回收的策略 是以这个引用计数为主,然后 标记清除 和 分代回收 只是做一个辅助性的手段;
46、curl 和 wget 有什么区别?
curl 是一个更加强大的网络访问工具,有非常强大的参数传递系统,不仅支持 HTTP 协议,还有像 FTP 这样的协议 非常非常多;
如果想简单的发送一个请求,用 wget 就可以;如果你要专职的测试这个网络,还是用 curl 会更加安心一些
47、什么是编码 和 解码?
编码是从一种形式或格式通过一定的规则转换成另外一种形式的过程;解码就是相反的;
比如说编程当中的字符串,我们经常需要通过 UTF-8格式 把他编码成二进制的格式;然后解码的过程是,把这个二进制的格式,在转换成字符串的格式;
48、序列化 和 反序列化 的区别?
简答来说 序列化,将对象转化成一个字节流的过程,反序列化,就是把字节流转化成一个对象的过程;
在接口自动化测试当中,我们经常需要把 编程语言的对象,转换成 json 格式,这个就是一个序列化的过程;
如果我们需要把 json 转化成 编程语言对象,这就是反序列化的过程
49、框架 和 库 有什么区别?
库 是代码的集合,供程序员调用;就是 库为我们提供了很多封装好的函数,看起来零零散散的,但是我们使用起来比较灵活;
而 框架 就是为了解决刻一个 或者 是为一类问题而设计的;框架为我们提供了一条龙服务一整套服务,经常会制定很多规则 或者 约束,一个框架呢通常来说会调用很多的库;
总的来说 库 更加灵活,而 框架使用起来会更加的方便
如果对你有帮助的话,点个赞收个藏,给作者一个鼓励,也方便你下次能够快速查找,感谢。
如果你想获取该文章配套的视频视频教程以及练手的接口。请狠狠点击文章末尾推广小卡片
并把所需的资料的文章链接发给我即可领取
如果你想获取简历模板+面试技术宝典+求职视频+上千份测试真题,
请狠狠点击文章末尾推广小卡片
并把所需的资料的文章链接发给我即可领取