自动测试LeetCode用例方法
自动合并测试LeetCode解题方法
在leetcode.com上答题,Run Code或者Sumbmit通常要Spending一会,如果提交一次就Accepted那还好,如果反复Wrong Answer,很耽误时间。为了调高效率和减少挫折(来回提交,一直Wrong Answer倍受打击),我采取在本地Jupyter notebook上coding,测试通过后再提交的方式。本篇主要介绍自动测试的方法。
1. LeetCode模式
打开leetcode一道题后,左侧有一个Description选项卡,该选项卡面板内有题目、命题描述、还列举了多个Example,每个Example都有一个Input和一个Output,有的还会有一个Explanation;右侧是coding区,coding区自动生成 class Solution模板。
class Solution: def method(self,**kwargs):
例如,第1071号题Decription区的Example内容如下

1071号题coding区初始化模板如下

2. Jupyter notebook编写代码
将LeetCode中coding模板内容复制到jupyter notebook中,编写解题代码。假如1071号题的代码如下。
class Solution:
def gcdOfStrings(self, str1: str, str2: str) -> str:
if len(str1) < len(str2):
tmp, str2, str1 = str2, str1, tmp
len_str2, len_str1 = len(str2), len(str1)
for i in range(1,len_str2+1):
d2,m2 = divmod(len(str2),i)
if m2==0 and str2==str2[:d2]*i:
d1, m1 = divmod(len(str1),d2)
if m1==0 and str1==str2[:d2]*d1:
return str2[:d2]
return ""
3. 手动逐一测试
手动逐一测试,就是编写好method内容后,实例化Solution,然后复制Decription中每个Example中的Input,传入实例的方法,执行后观察结果是否与Example中Output一致。
# 实列化类
s = Solution()
# 测试Example中的用例1
# Input: str1 = "ABCABC", str2 = "ABC"
# Output: "ABC"
str1 = "ABCABC"
str2 = "ABC"
s.gcdOfStrings(str1,str2)
'ABC'
# 测试Example中的用例2
# Input: str1 = "ABABAB", str2 = "ABAB"
# Output: "AB"
str1 = "ABABAB"
str2 = "ABAB"
s.gcdOfStrings(str1,str2)
'AB'
# 测试Example中的用例3
# Input: str1 = "LEET", str2 = "CODE"
# Output: ""
str1 = "LEET"
str2 = "CODE"
s.gcdOfStrings(str1,str2)
''
# 测试Example中的用例4
# Input: str1 = "ABCDEF", str2 = "ABC"
# Output: ""
str1 = "ABCDEF"
str2 = "ABC"
s.gcdOfStrings(str1,str2)
''
4. 自动合并测试
4.1 复制测试用例
从LeetCode问题页面复制所有Example内容,赋值给str_Examples。这里用3对双引号,内容可以原封不动。Example描述有规律,而且每个题的Example描述都是同样的模式,所以我们可以定义一个通用方法来获取测试用例。
str_Examples ="""Example 1:
Input: str1 = "ABCABC", str2 = "ABC"
Output: "ABC"
Example 2:
Input: str1 = "ABABAB", str2 = "ABAB"
Output: "AB"
Example 3:
Input: str1 = "LEET", str2 = "CODE"
Output: ""
Example 4:
Input: str1 = "ABCDEF", str2 = "ABC"
Output: ""
"""
4.2 定义获取用例方法
- 目标是把Input、Output提取出来,并成对组织好。
- 通过观察,可采用正则化split、字符串split、replace、strip等方法提取Input、Output内容
- 输入参数和输出存入list,每个用例可能有多个参数,所以用例参数用dict装载,方便调用测试方法时用**kwargs传入。
注意:因为输入用例文档用的""""",引号里内容还含有双引号",split后会把里面的引号当做字符内容,导致结果出乎意料。
def get_test_cases(str_examples):
import re
params =re.split('Example.+?:',str_examples.replace('\n','').replace(' ',''))[1:]
cases_arg, cases_ans = [], []
for param in params:
kawargs = {}
args_,ans = param.split('Output:')
args_ = args_.replace('Input:','').strip().split(',')
cases_ans.append(ans)
for arg in args_:
key,val = arg.split("=")
kawargs[key] = val
cases_arg.append(kawargs)
return zip(cases_arg, cases_ans)
4.3 定义自动测试方法
- leetcode每个题生成的默认代码类名都是Solution,但是函数名根据题目来取,因题而异。dir(Solution())能够获取Solution的方法名列表,前面部分是内建方法名,最后一个是自定义的解题方法(这里考虑只有一个自建函数)。用dir(Solution())[-1]获取函数名,然后使用getattr获取实例方法f。
- 传入参数为get_usecases返回的结果——zip打包的测试用例输入和输出,for迭代或取每一个测试用例的输入参数kwargs(Example中的Input)和输入answer(Example中的Output)。
- 迭代测试用例,断言 f(**kwargs) == answer 。如果每个断言成功,返回'Accepted',否则try...except捕获断言失败,返回'Wrong Answer'。
def auto_test(test_cases):
f = getattr(Solution(), dir(Solution())[-1])
try:
for kwargs, answer in test_cases:
print(kawargs,answer)
assert f(**kwargs) == answer
return 'Accepted'
except Exception as e:
print(e)
return 'Wrong Answer'
4.4 what?! 神奇问题bug ?
- 先调用get_test_cases获取测试用例,然后将结果传入auto_test进行测试,结果是'Wrong Answer';
- 直接调用auto_test(get_test_cases()),结果也是'Wrong Answer'。
- 然而调用get_test_cases获取测试用例test_cases后,先迭代一遍test_cases,再将test_cases传入auto_test,结果为'Accepted'。
test_cases = get_test_cases(str_Examples)
auto_test(test_cases)
name 'kawargs' is not defined
'Wrong Answer'
auto_test(get_test_cases(str_Examples))
name 'kawargs' is not defined
'Wrong Answer'
for input_args,out in test_cases:
print(input_args, out)
auto_test(test_cases)
{'str1': '"ABABAB"', 'str2': '"ABAB"'} "AB"
{'str1': '"LEET"', 'str2': '"CODE"'} ""
{'str1': '"ABCDEF"', 'str2': '"ABC"'} ""
'Accepted'
4.5 编程陷阱
陷阱1:"""doc""",三对双引号中内容带引号,没去除引号被当做字符内容,导致Solution算法“失灵”。
doc = """ABC "efg" HIGK""" # efg带引号
doc.split() # 分割后'"efg"'而不是'efg',不注意还看不出来
['ABC', '"efg"', 'HIGK']
避坑办法:.replace('"','')去除内容引号
def get_test_cases(str_examples):
import re
params =re.split('Example.+?:',str_examples.replace('\n','').replace(' ',''))[1:]
cases_arg, cases_ans = [], []
for param in params:
kawargs = {}
args_,ans = param.split('Output:')
args_ = args_.replace('Input:','').strip().split(',')
# ans.replace('"','')
cases_ans.append(ans.replace('"',''))
for arg in args_:
key,val = arg.split("=")
# val.replace('"','')
kawargs[key] = val.replace('"','')
cases_arg.append(kawargs)
return zip(cases_arg, cases_ans)
陷阱2:try...except不仅捕获assert断言成功失败,在try中print(kawargs,answer),‘kawargs’写错也导致进入except块。
避坑办法:try...except Exception as e打印异常,debug错误
# 捕获except异常并不等于assert断言失败
try:
print(what)
assert 1==1
except Exception as e:
print(e)
name 'what' is not defined
def auto_test(test_cases):
f = getattr(Solution(), dir(Solution())[-1])
try:
for kwargs, answer in test_cases:
print(kwargs,answer)
assert f(**kwargs) == answer
return 'Accepted'
except Exception as e:
print(e)
return 'Wrong Answer'
陷阱2:zip只能迭代一次,looping后被释放,外部迭代一次后再传入auto_test,不进入for迭代,造成外部迭代后返回正确'Accepted'的假象。
val =[1,2,3]
key = ['a','b','c']
ziped = zip(key,val)
print('----first iter zip---------')
for (key,val) in ziped:
print(key,val)
print('----second iter zip---------')
for (key,val) in ziped:
print(key,val)
----first iter zip---------
a 1
b 2
c 3
----second iter zip---------
避坑办法:头一次掉这坑,刷新zip认知,记住它。
4.6 再次测试
test_cases = get_test_cases(str_Examples)
auto_test(test_cases)
{'str1': 'ABCABC', 'str2': 'ABC'} ABC
{'str1': 'ABABAB', 'str2': 'ABAB'} AB
{'str1': 'LEET', 'str2': 'CODE'}
{'str1': 'ABCDEF', 'str2': 'ABC'}
'Accepted'
auto_test(get_test_cases(str_Examples))
{'str1': 'ABCABC', 'str2': 'ABC'} ABC
{'str1': 'ABABAB', 'str2': 'ABAB'} AB
{'str1': 'LEET', 'str2': 'CODE'}
{'str1': 'ABCDEF', 'str2': 'ABC'}
'Accepted'
5. 总结
step1: 在Jupyter notebook中编写LeetCode问题解答代码
class Solution: def method(self,**kwargs):
step2: 复制LeetCode中Example内容复制给变量str_Examples
step3: 使用get_test_cases获取测试用例
step4: 调用auto_test进行自动测试,返回'Accepted'所有测试用例通过,'Wrong Answer'表示存在没能通过的用例。
LeetCode问题Description中所有Example测试通过,即Run Code结果为'Accepted',并不代表Submit后的结果一定会为'Accepted'。相反,Run Code结果为'Wrong Answer',那么Submit后结果一定是'Wrong Answer'。因为Description中的Example只是部分示例,是Submit后验证的测试用例集合的子集。
def get_test_cases(str_examples):
import re
params =re.split('Example.+?:',str_examples.replace('\n','').replace(' ',''))[1:]
cases_arg, cases_ans = [], []
for param in params:
kawargs = {}
args_,ans = param.split('Output:')
args_ = args_.replace('Input:','').strip().split(',')
# ans.replace('"','')
cases_ans.append(ans.replace('"',''))
for arg in args_:
key,val = arg.split("=")
# val.replace('"','')
kawargs[key] = val.replace('"','')
cases_arg.append(kawargs)
return zip(cases_arg, cases_ans)
def auto_test(test_cases):
f = getattr(Solution(), dir(Solution())[-1])
try:
for kwargs, answer in test_cases:
print(kwargs,answer)
assert f(**kwargs) == answer
return 'Accepted'
except Exception as e:
print(e)
return 'Wrong Answer'
自动测试LeetCode用例方法的更多相关文章
- PHP自动测试框架Top 10
对于很多PHP开发新手来说,测试自己编写的代码是一个非常棘手的问题.如果出现问题,他们将不知道下一步该怎么做.花费很长的时间调试PHP代码是一个非常不明智的选择,最好的方法就是在编写应用程序代码之前就 ...
- python unittest自动测试框架
编写函数或者类时进行测试,确保代码正常工作 python unittest 模块提供了代码测试工具.按照定义测试包括两部分:管理测试依赖库的代码(称为‘固件’)和测试本身. 单元测试用于核实函数的某 ...
- Testing - 测试基础 - 用例
测试用例 是指对一项特定的软件产品进行测试任务的描述,体现测试方案.方法.技术和策略. 内容包括测试目标.测试环境.输入数据.测试步骤.预期结果.测试脚本等,并形成文档. 每个具体测试用例都将包括下列 ...
- Apache JMeter--网站自动测试与性能测评
Apache JMeter--网站自动测试与性能测评 2013-02-28 15:48:05 标签:Jmeter From:http://bdql.iteye.com/blog/291987 出于学习 ...
- 通过Jasmine和Guard自动测试JavaScript
原文标题:Autotesting JavaScript with Jasmine and Guard 原文地址:http://edspencer.net/2013/06/15/autotesting- ...
- Win10电脑经常自动掉线、自动断网的解决方法
近期一客户称自己使用电脑上网的时候,过一段时间莫名其妙的出现自动掉线.自动断网的情况,那么遇到这个问题该怎么办?下面装机之家分享一下Win10电脑经常自动掉线.自动断网的解决方法,以Win7系统为例. ...
- Qtp自动测试工具
QTP是基于GUI界面的自动化测试工具,用于系统的功能测试. QTP录制的是鼠标和键盘的消息.QTP录制回放时基于windows操作系统的消息机制.QTP在录制时监听应用程序的消息,监听到之后把消息放 ...
- 3.4 自动测试初步《精通ASP.NET MVC 5》
概述 ASP.NET MVC 框架已被设计成易于建立自动测试,并易于采用诸如测试驱动开发(TDD)等的开发方法学.ASP.NET MVC 为自动化测试提供了一个理想平台. 从广义上讲,当今的 Web ...
- 浅谈PHP面向对象编程(六、自动加载及魔术方法)
6.0 自动加载及魔术方法 6.1 自动加载 在PHP开发过程中,如果希望从外部引入一个class.通常会使用incluae和requre方法把定义这个class的文件包含进来.但是,在大型的开发项 ...
随机推荐
- NOIP2012 解题报告
TG Day1 T3 开车旅行 1. 预处理出从每座城市两人分别会到达的两座城市. 用 set 可以轻松实现. 2. 用倍增优化 DP 令 \(f_{i,j,k}\) 表示从城市 \(j\) 出发,行 ...
- P2592 [ZJOI2008]生日聚会
容易发现已经结束掉的一个子串只要合法就对后面没有影响,所以可以令 \(f_{i,j,p,q}\) 表示前 \(i+j\) 个人有 \(i\) 个男孩,\(j\) 个女孩,所有后缀中男孩最多比女孩多 \ ...
- 2017年第八届蓝桥杯【C++省赛B组】B、C、D、H 题解
可能因为我使用暴力思维比较少,这场感觉难度不低. B. 等差素数列 #暴力 #枚举 题意 类似:\(7,37,67,97,127,157\) 这样完全由素数组成的等差数列,叫等差素数数列. 上边的数列 ...
- kafka入门之broker--日志存储设计
kafaka并不是直接将原省消息写入日志文件的,相反,它会将消息和一些必要的元数据信息大宝在一起封装成一个record写入日志.其实就是我们之前介绍的batch 具体对每个日志而言,kafka又将其进 ...
- Elements-of-Python_02_DataType
(内容包括数据类型,运算符) 1.数据类型Data Types 1.1 简介Brief Introduction Python3中的数据类型,类型关键字,赋值,见下表: 1.1数字Number Pyt ...
- js中定时器调用函数时为什么会有引号
之前在学习的时候并没有发现的细节,关于js中,定时器的问题 这里我们写两个延时器 setTimeout(func, 0); setTimeout("func()", 0);定时器中 ...
- CenOS下监控工具尝试
Cacti cacti重图形,有数据历史,需要用到数据库支持,支持web配置,默认不支持告警,可以加插件. Server端配置 安装epel yum install -y epel-release 安 ...
- day102:MoFang:后端完成对短信验证码的校验&基于celery完成异步短信发送&flask_jwt_extended&用户登录的API接口
目录 1.用户注册 1.后端完成对短信验证码的校验 2.基于celery实现短信异步发送 2.用户登录 1.jwt登录验证:flask_jwt_extended 2.服务端提供用户登录的API接口 1 ...
- 本人的CSDN博客
本人的CSDN博客链接: 传送门
- js去除html标签
<script> //替换掉所有的 html标签,得到html标签中的内容 var content = "<p><font color=#000000>没 ...