使用Pytest解决Python中的算法问题(2019)

2020-12-19 23:47:13

我偶尔会喜欢解决算法问题,例如Project Euler或Code Advent,自从我还是个PHP小子以来就一直在做这些事情,与我在英国的信息学奥林匹克竞赛中在英国的同龄人竞争。和非常有趣。

技术面试经常在技术面试中使用,我觉得这没什么好玩的。

无论哪种情况,使用自动化测试都会使这些问题更容易解决,我希望我早点知道!

在线算法平台(例如Codility)提供了自己的自动化测试,您可以在一些示例中将其用于基本验证,但是边缘案例被保留以供最终标记。为确保您的解决方案涵盖所有基础,您需要编写自己的测试。

在Python中,没有比Pytest更好的测试框架-我在所有开放源代码项目中都使用了它。它使您可以轻松地为任何Python代码添加测试,并且比Python的内置单元测试好得多。

让我们一起使用Pytest来看一个小问题。这是问题陈述:

编写一个函数solve(items),该函数接受项,一个整数列表,并返回列表中出现的大于0的最小整数;如果不存在,则返回0。

首先,让我们写一个最基本的求解函数草图。由于0是默认值,如果总是返回,我们可以给一些简单的分数打分。创建一个名为example.py的文件,内容如下:

让我们通过在Python 3解释器中运行功能来手动测试该功能。打开命令行并运行示例:

$ pythonPython 3.7.3(默认值,Apr 14 2019,21:08:36)[dar 10.0.1(clang-1001.0.46.3)] on darwinType" help&#34 ;," copyright" ,"信用"或"许可证"有关更多信息。来自示例importsolve>>> resolve([1,2])0>>解决([-1])0

每次修改代码时这样做都会很快变得很累,我们必须重新启动解释器,重新运行导入和测试,并手动比较输出结果。在尝试正确解决问题之前,现在编写自动化测试可以使整个循环更快,这也使我们可以提前考虑所有情况。

让我们编写测试并使用“红色,绿色,重构”模式解决问题。

Pytest可以与代码位于同一文件中的测试一起工作,其名称以test_开头的简单函数。我们使用Python的assert语句将代码的结果与期望值进行比较。

def Solve(items):返回0 def test_example_1():assert求解([1,2])== 1 def test_example_2():assert求解([-1])== 0

$ python -m pip install pytest正在收集pytest下载...成功安装了atomicwrites-1.3.0 attrs-19.1.0 more-itertools-7.0.0 pluggy-0.9.0 py-1.8.0 pytest-4.4.1六-1.12。 0 $ pytest example.py ============================测试会话开始============= ==================平台达尔文 - 的Python 3.7.3,pytest-4.4.1,PY-1.8.0,pluggy-0.chainz.0rootdir:/用户/ chainz / tmp / pytest_algos收集了2个项目example.pyF。[100%] ===================================失败=================================== ________________________________ test_example_1 ________________________________ def test_example_1():>断言solve([1,2])== 1E断言0 == 1E +其中0 = Solve([1,2])example.py:5:AssertionError =============== ======== 1个失败,1个通过了0.03秒======================

在输出的中间,我们可以看到example.py正在运行中的测试.Pytest为失败的测试输出一个F和一个dot。对于过去的。

FAILURES部分以失败的行扩展到失败,然后显示Solve([1,2])返回0,该结果不等于期望值1。

我们的测试只是一个开始,但并不能涵盖所有情况。我们没有包含0的列表,还缺少两个极端:空列表和1,000,000个项目的列表,长列表也可能包含很多取负整数或正整数,因此我们应同时尝试这两种方法。

让我们添加更多测试。通过将简短列表相乘,我们可以在Python中列出1,000,000个项目。在文件末尾添加以下测试:

def test_empty_list():断言解决([])== 0 def test_list_with_zero():断言解决([0,2])== 2 def test_long_positive_list():断言解决([1,2,3,4] * 250_000 )== 1 def test_long_negative_list():断言求解([-1,-2,-3,-4] * 250_000)== 0

=============================测试会话开始=================== =====================================================达尔文平台-python 3.7.3,pytest-4.4.1,py-1.8.0,pluggy-0.9.0rootdir:/ Users / chainz / tmp / pytest_algos收集了6个项目示例。 py F..FF。 [100%] ==================================失败========== ======================== ________________________________ test_example_1 ________________________________ def test_example_1():>断言solve([1,2])== 1E断言0 == 1E +其中0 = Solve([1,2])example.py:6:AssertionError_____________________________ test_list_with_zero ______________________________ def test_list_with_zero():>断言solve([0,2])== 2E断言0 == 2E +其中0 = Solve([0,2])example.py:18:AssertionError___________________________ test_long_positive_list ____________________________ def test_long_positive_list():>断言solve([1、2、3、4] * 250_000)== 1E断言0 == 1E +其中0 = solve(([1、2、3、4] * 250000))example.py:22:AssertionError ====================== 3个失败,其中3个通过了0.08秒===================== ==

现在我们可以尝试使所有测试都通过的解决方案,第一次尝试解决:

defsolve(项目):项目中的i的最小值= 0:如果最小值== 0或i<最小:最小=我返回最小

=============================测试会话开始=================== ==================================================达尔文平台-python 3.7.3,pytest-4.4.1,py-1.8.0,Pluggy-0.9.0rootdir:/ Users / chainz / tmp / pytest_algos收集了6个项目示例。 py .F ... F [100%] ===================================失败=== ================================ ________________________________ test_example_2 ________________________________ def test_example_2():>断言solve([-1])== 0E断言-1 == 0E + -1 = Solve([-1])example.py:14:AssertionError___________________________ test_long_negative_list ____________________________ def test_long_negative_list():>断言solve([-1,-2,-3,-4] * 250_000)== 0E断言-4 == 0E +其中-4 = solve(([[-1,-2,-3,-4] * 250000))example.py:30:AssertionError ====================== 2次失败,其中4次通过了0.17秒=========== ============

现在我们有两种不同的失败方法,看来我们还没有忽略负数,糟糕透顶!

defsolve(项):项中i的最小值= 0,如果i&gt; 0和(最小值== 0或i <最小值):最小值=我返回最小值

重新运行测试会产生与上面相同的通行输出。是的,我们将代码简化为一行!

希望本教程对您有所帮助,并且您可以使用此技术来升级算法游戏,

在Django项目上工作? 查看我的《加快Django测试速度》一书,其中涵盖了许多最佳实践,因此您可以编写更快,更准确的测试。