自动合并测试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用例方法的更多相关文章

  1. PHP自动测试框架Top 10

    对于很多PHP开发新手来说,测试自己编写的代码是一个非常棘手的问题.如果出现问题,他们将不知道下一步该怎么做.花费很长的时间调试PHP代码是一个非常不明智的选择,最好的方法就是在编写应用程序代码之前就 ...

  2. python unittest自动测试框架

    编写函数或者类时进行测试,确保代码正常工作 python  unittest 模块提供了代码测试工具.按照定义测试包括两部分:管理测试依赖库的代码(称为‘固件’)和测试本身. 单元测试用于核实函数的某 ...

  3. Testing - 测试基础 - 用例

    测试用例 是指对一项特定的软件产品进行测试任务的描述,体现测试方案.方法.技术和策略. 内容包括测试目标.测试环境.输入数据.测试步骤.预期结果.测试脚本等,并形成文档. 每个具体测试用例都将包括下列 ...

  4. Apache JMeter--网站自动测试与性能测评

    Apache JMeter--网站自动测试与性能测评 2013-02-28 15:48:05 标签:Jmeter From:http://bdql.iteye.com/blog/291987 出于学习 ...

  5. 通过Jasmine和Guard自动测试JavaScript

    原文标题:Autotesting JavaScript with Jasmine and Guard 原文地址:http://edspencer.net/2013/06/15/autotesting- ...

  6. Win10电脑经常自动掉线、自动断网的解决方法

    近期一客户称自己使用电脑上网的时候,过一段时间莫名其妙的出现自动掉线.自动断网的情况,那么遇到这个问题该怎么办?下面装机之家分享一下Win10电脑经常自动掉线.自动断网的解决方法,以Win7系统为例. ...

  7. Qtp自动测试工具

    QTP是基于GUI界面的自动化测试工具,用于系统的功能测试. QTP录制的是鼠标和键盘的消息.QTP录制回放时基于windows操作系统的消息机制.QTP在录制时监听应用程序的消息,监听到之后把消息放 ...

  8. 3.4 自动测试初步《精通ASP.NET MVC 5》

    概述 ASP.NET MVC 框架已被设计成易于建立自动测试,并易于采用诸如测试驱动开发(TDD)等的开发方法学.ASP.NET MVC 为自动化测试提供了一个理想平台. 从广义上讲,当今的 Web ...

  9. 浅谈PHP面向对象编程(六、自动加载及魔术方法)

    6.0 自动加载及魔术方法  6.1 自动加载 在PHP开发过程中,如果希望从外部引入一个class.通常会使用incluae和requre方法把定义这个class的文件包含进来.但是,在大型的开发项 ...

随机推荐

  1. 学习netty遇到的关于 LineBasedFrameDecoder 的问题

    最近在看<Netty权威指南>这本书,关于TCP粘包/拆包,书中使用的是 LineBasedFrameDecoder 来解决的,但是我在实践的过程中出现了问题,上代码吧. 这个是 serv ...

  2. JAVA面试宝典分享

    JAVA面试宝典分享 前言 面试题 Java面试题(上) Java面试题(中) Java面试题(下) 参考答案 其他补充内容: 项目经验 项目介绍 项目开发流程 项目管理 系统架构 第三方工具(插件) ...

  3. 【ACwing 98】分形之城——分形

    (题面来自ACwing) 城市的规划在城市建设中是个大问题. 不幸的是,很多城市在开始建设的时候并没有很好的规划,城市规模扩大之后规划不合理的问题就开始显现. 而这座名为 Fractal 的城市设想了 ...

  4. Linux 学习笔记01丨Ubuntu系统安装、配置及软件教程集合

    1. Ubuntu系统安装 Windows10安装ubuntu18.04双系统教程 Ubuntu 20.04.1 镜像下载 软碟通 机械革命进入BIOS模式 要按F2,注意将Boot Option中将 ...

  5. 【mq读书笔记】顺序消息

    注意异常情况导致整个消费无限重试 阻塞消费 mq支持局部消息顺序消费,可以确保同一个消息消费队列中的消息被顺序消费.看下针对顺序消息在整个消费过程中做的调整: 队列负载: DefaultMQPushC ...

  6. vue跨域请求

    浏览器的同源策略 同源 协议相同 域名相同 端口相同 同源目的 保证用户信息安全,防止恶意的网站窃取数据 同源策略解决方法 jsonp cors 代理解决跨域 settings.py INSTALLE ...

  7. 转载的一篇文章eclipse添加插件

    eclipse没有(添加)"Dynamic Web Project"选项的方法 转载海边的第八只螃蟹 最后发布于2015-11-24 21:24:15 阅读数 40814  收藏 ...

  8. 20200203_windows2012下安装mysql 5.7.29

    一.   检查系统版本: 二. 下载mysql, 下载地址: https://dev.mysql.com/downloads/mysql/5.7.html#downloads 三.   解压下载后的压 ...

  9. Python(Python+Qt)学习随笔:使用xlwings新建Execl文件和sheet的方法

    在<Python学习随笔:使用xlwings读取和操作Execl文件>介绍了使用xlwings读取和操作Execl文件的方法,但老猿这两天写个例子使用时,发现使用该文的方法无法新建EXCE ...

  10. instanceof constructor Object.prototype.tostring.call ( [] )区别 数组和 对象的3中方法