文章目录

  • 一、接口自动化之Cookie, Session, Token
    • 1、Cookie
    • 2、Session
    • 3、Token鉴权
    • cookie,session,token的相同和区别
  • 二、自动化框架
    • 1、自动化框架了解
    • 2、单元测试框架对比
  • 三、Unittest框架
    • 3.1 TestCase用法
    • 3.2 用例的执行顺序
    • 3.3 TestFixture测试夹具
    • 3.4 unittest单元框架中的断言
    • 3.5 批量执行用例生成HTML格式的报告
  • 四、Pytest框架
    • 4.1 使用pytest,默认的测试用例规则及基础应用
    • 4.2 pytest执行测试用例的顺序
      • 1. 通过读取 pytest.ini 配置文件运行
      • 2. 如何分组执行(冒烟,分模块执行,分接口和web执行)
      • 3. pytest跳过测试用例
    • 4.3 pytest框架实现的一些前后置处理(固件、夹具)
      • 1. setup/teardown,setup_class/teardown_class
      • 2. 使用`@pytest.fixture()`装饰器来实现==部分==用例的前后置
      • 3. 通过`conftest.py`和@pytest.fixture()结合使用实现==全局==的前置应用
    • 4.4 断言
    • 4.5 pytest 结合 allure-pytest 插件生成 allure 测试报告

一、接口自动化之Cookie, Session, Token

1、Cookie

  • 什么是Cookie?
    Cookie是在服务器产生的,存储在客户端的一小段文本信息,格式是字典(键值对)

  • Cookie的分类
    会话级:保存在内存,当浏览器关闭就会丢失
    持久化:保存硬盘,只有当失效时间到了才会被清除

  • Cookie如何实现鉴权
    当客户端第一次访问服务器,服务器就会产生cookie,然后通过响应头的方式在Set-Cookie里面传输到客户端。客户端从第2-N次请求,都会自动带上这些Cookie

  • 弱点:Cookie保存在客户端,对于一些敏感信息,用户名、密码等不安全

  • 代码示例

import re
import unittestimport requests'''
cookie 鉴权
'''
class CookieJiangquan(unittest.TestCase):# token鉴权csrf_token = ""csrf_cookie = ""def test_01_index(self):url = "http://192.168.80.80/phpwind"res = requests.get(url)# 此时获取token,下面的接口方法需要# 通过正则表达式获取value = re.search('name="csrf_token" value="(.+?)"',res.text)CookieJiangquan.csrf_cookie = value.group(1)  # 第一个查询到的值CookieJiangquan.csrf_cookie = res.cookies   # cookie使会话连接def test_02_login(self):url = "http://192.168.80.80/phpwind/index.php?m=xx&x=jj"data = {"username":"admin","password":"pwd","csrf_token":CookieJiangquan.csrf_token}headers = {"Accept":"application/json","X-Requestd-With":"XMLHttpRequest"}# 手动带上cookie信息进行请求res = requests.post(url,data=data,headers=headers,cookie=CookieJiangquan.csrf_cookie)

2、Session

  • 当用户一次访问服务器的时候,在服务器端保存一个sessionid,这个sessionid是经过加密的,然后通过cookie把这个sessionid保存到客户端,然后请求服务器的时候只发送sessionid。
  • 代码示例
class CookieJiangquan(unittest.TestCase):# 全局变量session =  requests.session()# 直接使用session来进行请求,保持为一个对话res = CookieJiangquan.session.get(url)...res = CookieJiangquan.session.post(url,data=data,headers=headers)
  • 弱点:解决了cookie不安全的问题,但也产生了新的问题。当用户量特别大时,会导致服务器崩溃。

3、Token鉴权

  • 当一个用户登录之后,就给他发送一个token令牌,下一次用户再次请求的时候,只需要带上这个令牌。token是可以通过抓包抓取的。
    加密:
    对称加密:DES,AES
    双钥加密:RSA
    只加密不解密:MD5,SHA
  • token的分类
    access_token:有时间限制,一般在15分钟
    refresh_token:一般15天

cookie,session,token的相同和区别

  • 相同点:都是用于做鉴权的,都是服务器产生的
  • 区别:
    • cookie存储在客户端,session存储在服务器端,session的安全性比cookie高,一般情况下把重要的信息放在session,把不重要的放在cookie
    • session是存在服务器的内存,token存在服务器的文件或者数据库中,token的好处是比session更省服务器的资源,token只需要在服务器解密即可
  • 自动化层面:
    工具:postman,jmeter
    代码:接口关联,cookie鉴权,session鉴权,web自动化用cookie跳过验证码

二、自动化框架

1、自动化框架了解

  • 什么是框架?
    框架其实是开发定制研发的应用骨架,是一个半成品,它对基础的代码进行了封装并提供一些API接口。其他开发者只需要调用封装好的API接口即可,可以省去很多代码编写,从而提高工作效率
  • 自动化框架以及它的作用
    (1) 自动化测试框架
    自动化测试leader为了对一个系统做自动化测试而封装的一个代码主骨架,其他自动化测试工程师只需要去调用这个骨架里面的方法就可以实施自动化测试,这个代码骨架就叫自动化框架。
    (2) 自动化框架的作用
    – 提高测试效率,降低维护成本
    – 减少人工干预脚本因素
    – 增加代码的可重用率
    (3) unittest单元测试框架和自动化测试框架的关系
    – 单元测试:针对我们程序的最小单元(方法)进行测试
    – unittest是自动化框架的重要组成部分之一
    (pom,ddt数据驱动,全局配置封装,selenium二次封装,日志监控,断言,邮件发送)

2、单元测试框架对比

基于python语言:unittest和ptest
基于java语言:junit和testing

  1. 用例编写规则

unittest:提供了testcases测试用例、testsuites测试套件、testfixtures夹具、testloader测试加载器、testrunner测试运行器,必须遵守以下规则:

  • 测试文件必须先导入 import unittest
  • 测试类必须继承unittest.TestCase
  • 测试方法必须以test开头

pytest:它是python的第三方测试框架,基于unittest的扩展框架,必须遵守以下规则:

  • 测试文件名必须以test_开头或者_test结尾
  • 测试类命名必须以Test开头
  • 测试方法必须以test开头
  1. 用例的前置和后置
  • unittest:
    setUp/testDown:在每个用例之前或者之后运行一次(打开浏览器,加载网页/关闭网页)
    setUpClass/testDownClass:在每个类运行之前或者之后运行一次(创建数据库连接/创建日志对象/关闭数据库连接/销毁日志对象)
    setUpModule/testDownModule:在每个模块之前或者之后运行一次
  • pytest:
    方法级:setup_method/teardown_method 在方法之前和之后
    setup/teardown
    函数级:
    setup_function/teardown_function 在函数之前和之后
    类级别:
    setup_calss/teardown_class
    模块级别:
    setup_module/teardown_module
    还有:可以在函数之前加@pytest.fixture()
  1. 断言
    unittest:assertTrue,assertEqual,assertIn
    pytest:assert

  2. 报告
    unittest:htmltestrunner
    pytest:插件:pytest-HTML,allure

  3. 失败重跑
    unittest:没有
    pytest:pytest-rerunfailures插件

  4. 数据驱动
    unittest:ddt
    pytest:@pytest.mark.parametrize装饰器

  5. 用例分类执行
    unittest:默认执行所有,也可以通过testsuite来执行部分用例,或者-k参数
    pytest:@pytest.mark

三、Unittest框架

  1. unittest框架主要做了什么
    – 测试发现:从多个py文件中收集并加载测试用例
    – 测试执行:将测试用例按照一定的顺序和条件去执行并且生成结果
    – 测试判断:通过断言去判断结果是否正确
    – 测试报告:统计测试进度,通过率,生成报告
  2. unittest重要组件
    TestCase: 测试用例
    TestSuite:测试套件
    TestFixture:夹具
    TestLoader:测试加载器
    TestRunner:测试运行器

3.1 TestCase用法

import unittestclass EcshopLogin(unittest.TestCase):# 测试用例def test01_baili(self):print("测试unittest")
  1. 使用unittest命令行的方式运行
    python -m unittest -v ecshop_login.EcshopLogin.test01_baili
    python -m 以脚本的方式运行一个模块
    unittest -v 更详细的输出结果
    ecshop_login.EcshopLogin.test01_baili:模块名.类名.方法名
    -k 匹配模式:
    通配符:-k *_weiwei
    字符串:-k weiwei
  • 集成 jenkins 的时候使用,所有的命令行方式都为非GUI方式
    postman: 非GUI,newman
    jmeter: jmeter命令
  1. 使用unittest.main(),以模块的方式运行
if __name__ == '__main__':unittest.main()

配置pycharm的环境 或者 命令行运行:D:\PyCharm\Code\demo2>python ecshop_login.py

  1. 用例的执行结果:
    . 成功
    F 失败
    E 错误
    S 跳过
 # 测试用例@unittest.skip("此用例不执行")   # sdef test01_baili(self):raise Exception("自定义异常")   # Errorself.assertTrue(0) # Failureprint("测试unittest")def test02_weiwei(self):  # 成功.print("测试微微")

3.2 用例的执行顺序

按ASCII码的规则:【0-9 A-Z a-z】 A=65 a=97

import os
import unittestclass EcshopLogin(unittest.TestCase):# 测试用例# @unittest.skip("此用例不执行")   # sdef test01_baili(self):# raise Exception("自定义异常")   # Error# self.assertTrue(0) # Failureprint("测试unittest")def test02_weiwei(self):  # 成功.print("测试微微")def test03_xiexie(self):print("测试谢谢")if __name__ == '__main__':...
  • 使用套件可以指定执行 suite = unittest.TestSuite()
# 加载单个用例 suite.addTest
suite.addTest(EcshopLogin("test01_baili"))
# 加载多个用例 suite.addTests
testcases = [EcshopLogin("test01_baili"),EcshopLogin("test02_weiwei")]
suite.addTests(testcases) # 找到所有用例testcases = unittest.defaultTestLoader.discover(start_dir=os.getcwd(),pattern='*.py')
  • 执行
# unittest.main(defaultTest='suite')unittest.TextTestRunner().run(suite)  # 与上面的执行方式是同样的

3.3 TestFixture测试夹具

  • 将夹具进行二次封装,写在一个类之中,而写有测试用例的类,只需要去继承这个类,就可以拥有这些方法。
'''
很少用到:def setUpModule():print("模块级的夹具---开始")def tearDownModule():print("模块级的夹具—--结束")
'''class MyUnit(unittest.TestCase):@classmethoddef setUpClass(cls):print("setUpClass:每个类之前执行一次,例如创建数据库,生成日志对象")def setUp(self):print("\nsetUp:测试用例前的准备工作,例如打开浏览器,加载网页")def tearDown(self):print("tearDown:测试用例之后的扫尾工作,例如关闭浏览器")@classmethoddef tearDownClass(cls):print("tearDownClass:每个类之后执行一次,例如关闭数据库链接,销毁日志对象")
from my_unit import MyUnit# 继承
class Test2(MyUnit):def test01_weiwei(self):  # 成功.print("测试2")
  • 忽略测试用例 skip
    可以作用在类上(较少),也可以作用在方法上(忽略一些不想执行的用例)
@unittest.skip("此模块暂不测试")
class EcshopLogin(MyUnit):age = 22# 测试用例@unittest.skip("此用例不执行")   def test01_baili(self):print("测试unittest")@unittest.skipIf(age>=18 and age<=25,"如果满足条件就忽略")def test02_weiwei(self): print("测试微微")@unittest.skipUnless(age<18,"如果不满足条件则忽略")def test03_xiexie(self):print("测试谢谢")

3.4 unittest单元框架中的断言

断言
assertEqual(a,b) 断言 a==b
assertNotEqual(a,b) 断言 a!=b
assertTrue(a) 断言a为真
assertFalse(a) 断言a为假
assertIn(a,b) 断言a在b里
assertNotIn(a,b) 断言a不在b里

3.5 批量执行用例生成HTML格式的报告

需要下载HTMLTestRunner.py文件
参考文章进行修改:HTMLTestRunner使用方法

  • 官网下载的文件不支持python3.x
  • 使用之前需要先进行导入 from HTMLTestRunner import HTMLTestRunner
import os
import unittest
from HTMLTestRunner import HTMLTestRunnerif __name__ == '__main__':suite = unittest.TestSuite()testcases = unittest.defaultTestLoader.discover(start_dir=os.getcwd(), pattern='*.py')suite.addTests(testcases)# unittest.TextTestRunner(verbosity=2).run(suite)  # 详细输出verbosity=2,默认1nowtime = time.strftime("%Y-%m-%d %H-%M-%S",time.localtime()) # 格式化时间name = open(os.getcwd()+"/"+nowtime+"_report.html","wb")runner = HTMLTestRunner(stream=name,verbosity=2,title="测试报告",description="报告详细如下:")runner.run(suite)
  • 运行示例:
    def test01_paopao(self):"""测试天天"""   # 注解print("测试1")self.assertEqual(1,2) # 错误

四、Pytest框架

  1. pytest简介
  • pytest是一个非常成熟的python的单元框架,比unittest更灵活,容易上手
  • pytest可以和selenium,requests,appium结合实现web自动化,接口自动化,app自动化
  • pytest可以实现测试用例的跳过以及reruns失败用例重试
  • pytest可以和allure生成非常美观的测试报告
  • pytest有很多非常强大的插件,并且这些插件可以实现很多实用的操作
    pytest-html (生成html格式的自动化测试报告),
    pytest-xdist (测试用例分布执行,多CPU分发),
    pytest-ordering (用于改变测试用例的执行顺序),
    pytest-retunfailures (用例失败后重跑),
    allure-pytest (用于生成美观的测试报告)
  1. pytest插件下载
    在项目的根目录下新建文件requirements.txt,在里面写需要的插件名称,然后通过命令一次性下载:pip install -r requirements.txt

4.1 使用pytest,默认的测试用例规则及基础应用

  • 书写规则

    • 块名必须以test_开头或者_test结尾
    • 测试类必须以Test开头,并且不能有init方法
    • 测试方法必须以test开头
  • pytest测试用例的运行方式
    • 主函数模式
      (1)运行所有:pytest.main()
      (2)指定模块:pytest.main(['-vs','test_login.py'])
      (3)指定目录:pytest.main(['-vs','./new_testcase'])
      (4)通过nodeid指定用例运行:nodeid是由模块名,分隔符,类名,方法,函数名组成
      pytest.main(['-vs','./new_testcase/test_newtest.py::test_04_func'])
    • 命令行模式
      (1)运行所有:pytest
      (2)指定模块:pytest -vs test_login.py
      (3)指定目录:pytest -vs ./new_testcase
      (3)指定nodeid:pytest -vs ./new_testcase/test_newtest.py::test_04_func
    • 通过读取pytest.ini配置文件运行
  • 参数详解:
    -s:表示输出调试信息,包括print打印的信息
    -v:显示更详细的信息
    -n:支持多线程或者分布式运行测试用例(如:pytest -vs ‘./testcase’ -n 2)
    –rerun NUM:失败用例重跑(pytest -vs ./testcase --reruns 2)
    -x:表示只有有一个用例报错,那么测试停止
    –maxfail=2:出现两个用例失败就停止
    -k:根据测试用例的部分字符串指定测试用例(pytest -vs ./testcase -k “cc”)
    –html ./report/report.html:生成html的测试报告

4.2 pytest执行测试用例的顺序

unittest:ascll码的大小来决定执行的顺序
pytest:默认从上到下

  • 改变默认的执行顺序:使用mark标记
1. 通过读取 pytest.ini 配置文件运行
  • pytest.ini 这个文件是pytest单元测试框架的核心配置文件(一般放在项目的根目录)
  • 编码:文件编码必须是ANSI,可以使用notepad++修改编码格式
  • 作用:改变pytest的默认行为
  • 运行规则:不管是主函数还是命令行的模式运行,都会去读取这个配置文件
[pytest]
addopts = -vs              # 命令行的参数,用空格分隔
testpaths = ./testcase      # 测试用例的路径
python_files = test_*.py   # 模块名的规则
python_classes = Test*     # 类名的规则
python_functions = test_*  # 方法名的规则
markers =                  # 可以自定义分组smoke:冒烟用例usermanage:用户管理productmanage:商品管理
2. 如何分组执行(冒烟,分模块执行,分接口和web执行)

smoke:冒烟用例,分布在各个模块中
pytest -vs -m “smoke or usermanage”

@pytest.mark.smoke
def test_02_aa(self):print("这是百丽2")# assert 1==2@pytest.mark.usermanage
def test_03_bb(self):print("这是百丽3")
3. pytest跳过测试用例
  1. 无条件跳过
  2. 有条件跳过

4.3 pytest框架实现的一些前后置处理(固件、夹具)

1. setup/teardown,setup_class/teardown_class

注意:和unittest不一样,pytest全是小写

class TestMashang:# 在所有用例之前只执行一次def setup_class(self):print("在每个类执行前的初始化工作:比如创建日志对象,创建数据库")# 在每个用例之前执行一次def setup(self):print("在执行测试用例之前执行的代码: 打开浏览器,加载网页")def test_05_meili(self):print("测试美丽")def teardown(self):print("在执行测试用例之后执行的代码: 关闭浏览器")def teardown_class(self):print("在每个类之后执行的扫尾工作,比如销毁日志对象,销毁数据库的连接")
2. 使用@pytest.fixture()装饰器来实现部分用例的前后置
@pytest.fixture(scope="",params="",autouse="",ids="",name="")
  • scope:表示是被@pytest.fixture标记的方法的作用域,function(默认),class,module,package,session
  • autouse:自动执行,默认False
import pytest# 如果希望所有方法都实现前置,则加上参数 autouse=True
@pytest.fixture(scope="function")
def my_fixture():print("这是前置的方法,可以实现部分以及全部用例的前后置")yieldprint("使用yield实现后置")class TestMashang():def test_05_meili(self):print("测试美丽")# 作为参数进行调用,实现前后置def test_06_biaoji(self,my_fixture):print("测试标记")
  • params:参数化(支持list[],tuple(),字典列表[{},{}],字典元组({},{}))
    注意:params是参数名,有s;request.param是属性名,没有s
@pytest.fixture(scope="function",params=['baby','xiao','shishi'])
def my_fixture(request):
# 使用request接收参数,使用request.param返回(固定写法)# return request.paramyield request.param  # return和yield都表示返回的意思,但是return后面不能有代码,而yield返回后面可以接代码# 可以写后置代码# 有三个参数,该用例会执行三次
def test_06_biaoji(self,my_fixture):print("测试标记")print('------------'+str(my_fixture))

  • ids:当使用params参数化时,给每一个值设置一个变量名,意义不大
  • name:给被@pytest.fixture标记的方法取一个别名
    当取了别名之后,原来的名称就用不了了
@pytest.fixture(scope="function",params=['成龙','萧','诗诗'],ids=['cl','xiao','shi'],name='aaaa')# 设置别名之后,引用也需要改为别名,否则会报错def test_06_biaoji(self,aaaa):print("测试标记")print('------------'+str(aaaa))
3. 通过conftest.py和@pytest.fixture()结合使用实现全局的前置应用
  • conftest.py文件是单独存放的一个夹具配置文件,名称不能更改
  • 用处:可以在不同的py文件中使用同一个fixture函数
  • conftest.py需要和运行的用例放在同一层,并且不需要做任何import导入操作

总结:
setup/teardown,setup_class/teardown_class 它是作用于所有用例或者所有的类
@pytest.fixture() 它的作用是既可以部分也可以全部前后置
conftest.py和@pytest.fixture() 结合使用,作用于全局的前后置

4.4 断言

 assert 1==2

4.5 pytest 结合 allure-pytest 插件生成 allure 测试报告

  1. 之前使用过pytest-html生成报告,但比较简单不美观
addopts = -vs --html ./report/report.html


2. allure的配置与安装

  • 下载,解压,配置path路径
    https://github.com/allure-framework/allure2/releases
    验证:allure --version
  • 生成json格式的临时报告
addopts = -vs --alluredir ./temp

  • 生成allure报告
if __name__ == '__main__':pytest.main()# allure generate固定语法 ./temp找到临时报告 -o 输出 到当前的 ./report目录下 --clean清空原有的报告os.system('allure generate ./temp -o ./report --clean')

Python自动化测试学习2相关推荐

  1. 怎么自学python自动化测试-学习自动化测试,如何学习Python语言?

    一.Python常用领域Python用于简单脚本编程,如编写2048小游戏或12306的自动抢票软件: Python用于系统编程,如开发系统应用: Python用于开发网络爬虫: 有资料奉上,可以看看 ...

  2. python自动化测试视频教程_精品系列-悠悠Python自动化测试学习视频,资源教程下载...

    课程名称 精品系列-悠悠Python自动化测试学习视频,资源教程下载 课程目录 第1课-http协议上 .mp4 第1课-http协议下.mp4 第2课-fiddler抓包与测试上.mp4 第2课-f ...

  3. python123测试_【测码学院】python自动化测试学习-自动化测试模型

    测码学院  python自动化测试学习 前言 自动化测试过程中,会通过模块的操作先后顺序进行代码编写,但对于整体性来说,需要先构建一个框架或者模型,便于后期对代码的维护,减少代码开发量以及维护成本.目 ...

  4. python自动化测试学习笔记合集

    python自动化测试学习笔记-1 一.什么是自动化 自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程.直白的就是为了节省人力.时间或硬件资源,提高测试效率,便引入了通过软件或程序自动化执行 ...

  5. python自动化测试学习路线(从入门到精通)

    目录:导读 一.Python的应用场景 二.自动化测试的那些事 三.主流自动化测试框架 三.Python自动化测试学习路线 写在最后 一.Python的应用场景 Python用于简单脚本编程,如编写2 ...

  6. 全栈Python自动化测试学习资料【付费资源、看到即赚到,】

    在测试行业从业了十多年积累了很多优秀的资料和素材,并且已经分门别类的整理好(不定期更新),从从0基础入门到高级课程,包含测试工具.学习资料(功能/性能/接口/自动化/app/web/思维导图).笔试面 ...

  7. python自动化测试学习笔记合集二

    python自动化测试学习笔记-4内置函数,处理json 函数.全局变量 写代码时注意的几点事项: 1.一般写代码的时候尽量少用或不用全局变量,首先全局变量不安全,大家协作的情况下,代码公用容易被篡改 ...

  8. python自动化测试学习笔记合集三

    上次我们学到了redis的一些操作,下面来实际运用以下. 这里我们先来学习一下什么是cookie和session. 什么是Cookie 其实简单的说就是当用户通过http协议访问一个服务器的时候,这个 ...

  9. python自动化测试学习路线

    一.Python的应用场景 Python用于简单脚本编程,如编写2048小游戏或12306的自动抢票软件: Python用于系统编程,如开发系统应用: Python用于开发网络爬虫: 网络爬虫的用途是 ...

  10. Python自动化测试学习哪些知识?

    Python自动化测试学习哪些知识?先学习自动化测试基础,学习Appium操作,元素定位.操作.等待.滑动等,深入讲解PO.unittest.yaml.配置文件.测试报告等知识,基于关键字驱动.Pyt ...

最新文章

  1. 线性回归之案例:波士顿房价预测
  2. 算法---------宝石与石头
  3. mysql每学科前两名 having_mysql 分组查询前n条数据
  4. Git版本库创建(包含文件权限设置 Linux环境下)
  5. [解决]Win7+Tomcat5.5 只能通过localhost或计算机名访问
  6. 计算机应用乘法,计算机系统原理(十) 二进制整数的乘法运算和除法运算
  7. vc6.0 绘制散点图_vc有关散点图的一切
  8. VS2017编译UE4.19.2报错
  9. newsinglethreadexecutor使用场景_java中Future的使用
  10. 从UDP/TCP到HTTP/HTTP2,弄清楚网络层面上应该了解的知识。
  11. 流式大数据计算实践(4)----HBase安装
  12. 马化腾一直都在闷声发财,马云却到处开课当导师
  13. ArchLinux安装简单安装教程
  14. python 卷积神经网络 应用_卷积神经网络在目标定位中的应用
  15. python贝叶斯网络预测模型_高效灵活的概率建模方法基于Python
  16. 我只用了3步,实现了一个逼真的3D场景渲染
  17. StarRocks 社区一周年:极速统一,感谢遇见!
  18. powerpoint预览_如何调整PowerPoint模板的大小
  19. c语言学习(循环语句do while)
  20. Nagios监控服务器与客户端的安装

热门文章

  1. 电脑xp传照片显示服务器错误,xp系统显示“服务器错误500”的两种解决方法
  2. B2092 开关灯 【入门】
  3. 路由交换技术与路由交换技术基础知识
  4. UDS汽车诊断入门01 - 简介
  5. PHP时间戳与日期的相互转换
  6. 呼唤IT企业的个人英雄主义
  7. Citrix 相关资料整理
  8. DevExpress 20.2.3有源码吗?一名鱼友刚刚问我的
  9. 为什么辞职(或裸辞)之后很难再找到工作,而且能力越高越明显?
  10. Leetcode Day10 最长公共子序列+字符串交织