跟着我们一起学 Python 30天课程-第20天-调试和测试

作者 : IT 大叔 本文共7436个字,预计阅读时间需要19分钟 发布时间: 2020-08-22

开发人员不会编写完美的代码,因此我们尝试构建的应用程序容易出现各种错误,异常或错误。不仅了解编程语言的语法和概念,还能够通过调试和编写测试来检测错误,以确保我们的代码可在不同的实际情况下工作。因此,为了能够使用Python编写高质量的代码,我探索了调试和测试的概念,主要是今天编写单元测试。

调试 Debugging

调试是计算机科学术语,用于在我们的代码中查找潜在的异常或错误。知道调试代码的概念以了解导致我们应用程序中不良行为的bug的原因非常方便。

Python附带了一些内置函数,这些工具可用于开箱即用地调试代码。调试代码更幼稚和更简单的方法通常是使用print我经常使用的语句。

main.py

def is_prime(num):
  if num > 1:
    for i in range(2,num):
        if (num % i) == 0:
            return False
    else:
        return True

  else:
    return False

result = is_prime('2')
print(result) # TypeError

上面的代码块给出了类型错误。现在,检查错误的简单方法是,我们可以放置一条print语句来了解函数内部正在发生的事情。

main.py

def is_prime(num):
    print(num) # 2 (Here using a print might confuse us!)
    if num > 1:
        for i in range(2, num):
            if (num % i) == 0:
                return False
        else:
            return True

    else:
        return False

result = is_prime('2')
print(result)

使用print语句来检查输入值可能会有些混乱,因为它看起来像一个数字。该函数是一个非常简单的示例,可能不需要使用这种关键分析,但通常了解调试问题的方式很有用。

为了充分利用调试功能,Python附带了内置模块pdb。它提供了许多有用的调试方法,例如set_trace()

main.py

import pdb

def is_prime(num):
    pdb.set_trace()
    if num > 1:
        for i in range(2, num):
            if (num % i) == 0:
                return False
        else:
            return True

    else:
        return False

result = is_prime('2')
print(result)

在运行程序时,解释器会在set_trace()调用位置暂停程序。现在,在调试控制台中,我们可以输入要在执行点检查其值的任何变量,例如num在这种情况下。它将立即显示为字符串的值“ 2”。因此,我们可以解决该问题。

从Python 3.7开始,有一种更好的方法是使用新方法进行调试,该方法breakpoint会自动调用该set_trace方法,是推荐的调试方法。

main.py

def is_prime(num):
    breakpoint() # places a breakpoint
    if num > 1:
        for i in range(2, num):
            if (num % i) == 0:
                return False
        else:
            return True

    else:
        return False

result = is_prime('2')
print(result)

现在,pdb控制台中提供了许多调试命令。只需键入即可help提供可用命令的列表。我想在此提供它们的列表以供参考。

Command Description
p Print the value of an expression.
pp Pretty-print the value of an expression.
n Continue execution until the next line in the current function is reached or it returns.
s Execute the current line and stop at the first possible occasion (either in a function that is called or in the current function).
c Continue execution and only stop when a breakpoint is encountered.
unt Continue execution until the line with a number greater than the current one is reached. With a line number argument, continue execution until a line with a number greater or equal to that is reached.
l List source code for the current file. Without arguments, list 11 lines around the current line or continue the previous listing.
ll List the whole source code for the current function or frame.
b With no arguments, list all breaks. With a line number argument, set a breakpoint at this line in the current file.
w Print a stack trace, with the most recent frame at the bottom. An arrow indicates the current frame, which determines the context of most commands.
u Move the current frame count (default one) levels up in the stack trace (to an older frame).
d Move the current frame count (default one) levels down in the stack trace (to a newer frame).
h See a list of available commands.
h Show help for a command or topic.
h pdb Show the full pdb documentation.
q Quit the debugger and exit.

调试资源 Debugging Resources

单元测试

我们的IDE和编辑器配备了许多工具功能,这些功能可以帮助我们使用诸如pylint之类的短绒棉纸编写更好的代码,并且减少错误。我们还可以调试代码以检查可能的错误原因。但是,更可靠,更有效的编程原则是通过编写单元测试来编写防御性代码,以确保我们的程序在不同的实际情况和边缘情况下运行。

编写测试通常听起来很无聊,乍看起来可能令人生畏。但是,它们非常有用,并且通过防止大量史无前例的错误,从长远来看可以节省大量时间和精力。它实际上还改善了我们的代码,并成为了很好的文档。对于程序员而言,阅读小型简单的单元测试以了解其功能而不是阅读大量文档会更加容易和实用。知道如何为我们的程序编写良好而简单的测试总是很高兴的。

Python再次使用内置模块为单元测试提供开箱即用的支持,unittest它也称为测试运行器,它可以一次对整个项目进行多个测试。

让我们尝试is_prime通过编写一些简单的测试来测试上述功能。为此,我们需要创建一个测试文件,在这种情况下test.py

test.py

import unittest
import main

class TestPrime(unittest.TestCase):
  def test_valid_type(self):
    test_input = 13
    test_result = main.is_prime(test_input)
    expected_result = True
    self.assertEqual(test_result, expected_result)

if(__name__ == '__main__'):
  unittest.main()

单元测试被编写为Python类,每个测试用例场景均被编写为该类中的单独方法。该类需要扩展unittest.TestCase该类。最后,还要进行检查以确保仅在从主模块运行时才启动单元测试。

然后可以使用python3 test.pypython3 test.py根据您的python设置运行测试文件。当测试场景符合功能标准时,上述测试应通过。

让我们尝试通过添加新方案来使测试失败。如果提供的输入不是有效输入,我们期望函数返回false。

test.py

import unittest
import main

class TestPrime(unittest.TestCase):
    def test_valid_type(self):
        test_input = 13
        test_result = main.is_prime(test_input)
        expected_result = True
        self.assertEqual(test_result, expected_result)

    def test_invalid_input(self):
        test_input = 'hello'
        test_result = main.is_prime(test_input)
        expected_result = False
        self.assertEqual(test_result, expected_result)

if (__name__ == '__main__'):
    unittest.main()

在这种情况下,第二次测试失败,因为我们尚未处理函数中可能发生TypeError的情况。因此可以相应地修改功能。

main.py

def is_prime(num):
    if (not isinstance(num, int)):
        return False
    if num > 1:
        for i in range(2, num):
            if (num % i) == 0:
                return False
            else:
                return True

    else:
        return False

现在,该函数处理无效输入,并且在这种情况下不会中断。让我们添加更多的测试用例。另一种方法是将代码try except块放在一个块中并在那里处理所有可能的异常。

test.py

import unittest
import main

class TestPrime(unittest.TestCase):
    def test_valid_type(self):
        test_input = 13
        test_result = main.is_prime(test_input)
        expected_result = True
        self.assertEqual(test_result, expected_result)

    def test_invalid_input(self):
        test_input = 'hello'
        test_result = main.is_prime(test_input)
        expected_result = False
        self.assertEqual(test_result, expected_result)

    def test_none_input(self):
        test_input= None
        test_result = main.is_prime(test_input)
        expected_result = False
        self.assertEqual(test_result, expected_result)

    def test_negative_input(self):
        test_input= -13
        test_result = main.is_prime(test_input)
        expected_result = False
        self.assertEqual(test_result, expected_result)

if (__name__ == '__main__'):
    unittest.main()

如果我们要在运行测试之前初始化一些变量或设置一些配置,则可以将其写入setup方法中。同样,在每次测试后,可以使用该teardown方法进行任何类型的清理。该setUp方法比该tearDown方法更经常使用。

import unittest
import main

class TestPrime(unittest.TestCase):
    def setUp(self):
        print('This will run before each test')

    def test_valid_type(self):
        test_input = 13
        test_result = main.is_prime(test_input)
        expected_result = True
        self.assertEqual(test_result, expected_result)

    def test_invalid_input(self):
        test_input = 'hello'
        test_result = main.is_prime(test_input)
        expected_result = False
        self.assertEqual(test_result, expected_result)

    def test_none_input(self):
        test_input = None
        test_result = main.is_prime(test_input)
        expected_result = False
        self.assertEqual(test_result, expected_result)

    def test_negative_input(self):
        test_input = -13
        test_result = main.is_prime(test_input)
        expected_result = False
        self.assertEqual(test_result, expected_result)

    def tearDown(self):
        print('this will run after each test')

if (__name__ == '__main__'):
    unittest.main()

这就是单元测试可以帮助我们改进代码并确保我们的代码在不同情况下不会中断的方式。此外,还可以确保新引入的功能不会破坏现有功能。

这里有一些很棒的资源,可以帮助您了解和探索有关Python单元测试的更多信息。

我希望我能够简要解释一下调试和测试Python代码的好处和用例。我们开始测试和调试的越多,我们就越了解这种语言并编写更好的代码。

今天就这些。明天,我将探讨如何使用Python出于多种目的创建脚本。

跟着我们一起学 Python 30天课程目录:

  1.  跟着我们一起学 Python 30天课程-第30天-免费Python资源 
  2.  跟着我们一起学 Python 30天课程-第29天-自动化测试 
  3.  跟着我们一起学 Python 30天课程-第28天-ML和数据科学II 
  4.  跟着我们一起学 Python 30天课程-第27天-ML和数据科学I 
  5.  跟着我们一起学 Python 30天课程-第26天-机器学习基础 
  6.  跟着我们一起学 Python 30天课程-第25天-Web 开发进阶
  7.  跟着我们一起学 Python 30天课程-第24天-Web开发基础 
  8.  跟着我们一起学 Python 30天课程-第23天-网页爬虫 
  9.  跟着我们一起学 Python 30天课程-第22天-脚本额外功能Scripting Extras 
  10.  跟着我们一起学 Python 30天课程-第21天-脚本编写基础 
  11.  跟着我们一起学 Python 30天课程-第20天-调试和测试 
  12.  跟着我们一起学 Python 30天课程-第19天-正则表达式 
  13.  跟着我们一起学 Python 30天课程-第18天-文件I / O 
  14.  跟着我们一起学 Python 30天课程-第17天-外部模块External Modules 
  15.  跟着我们一起学 Python 30天课程-第16天-模块基础Module Basics 
  16.  跟着我们一起学 Python 30天课程-第15天-生成器Generators 
  17.  跟着我们一起学 Python 30天课程-第14天-错误处理Error Handling 
  18.  跟着我们一起学 Python 30天课程-第13天-Decorators 
  19.  跟着我们一起学 Python 30天课程-第12天-Lambda Expressions & Comprehensions 
  20.  跟着我们一起学 Python 30天课程-第11天-函数编程Functional Programming基础 
  21.  跟着我们一起学 Python 30天课程-第10天-OOP Missing Pieces 
  22.  跟着我们一起学 Python 30天课程-第9天-OOP Pillars 
  23.  跟着我们一起学 Python 30天课程-第8天-OOP基础知识 
  24.  跟着我们一起学 Python 30天课程-第7天-开发环境搭建(Developer Environment) 
  25.  跟着我们一起学 Python 30天课程-第6天-循环II和函数(Loops II & Functions) 
  26.  跟着我们一起学 Python 30天课程-第5天-条件和循环I(Conditions & Loops I) 
  27.  跟着我们一起学 Python 30天课程-第4天-数据类型III(Data Types III) 
  28.  跟着我们一起学 Python 30天课程-第3天-数据类型II(Data Types II) 
  29.  跟着我们一起学 Python 30天课程-第2天-数据类型I(Data Types I) 
  30.  跟着我们一起学 Python 30天课程-第1天-简介 
免责声明:
1. 本站资源转自互联网,源码资源分享仅供交流学习,下载后切勿用于商业用途,否则开发者追究责任与本站无关!
2. 本站使用「署名 4.0 国际」创作协议,可自由转载、引用,但需署名原版权作者且注明文章出处
3. 未登录无法下载,登录使用金币下载所有资源。
IT小站 » 跟着我们一起学 Python 30天课程-第20天-调试和测试

常见问题FAQ

没有金币/金币不足 怎么办?
本站已开通每日签到送金币,每日签到赠送五枚金币,金币可累积。
所有资源普通会员都能下载吗?
本站所有资源普通会员都可以下载,需要消耗金币下载的白金会员资源,通过每日签到,即可获取免费金币,金币可累积使用。

发表评论