» Python创建命令行程序grep » 2. 开发 » 2.5 编写测试

编写测试

unittest 模块提供了一个编写和运行单元测试的框架。单元测试是一种测试软件的单独单元或组件,以确保它们自身是正常的。unittest 模块受 Java JUnit 测试框架的启发,遵循 xUnit 测试风格。

通过继承 unittest.TestCase 类来创建测试用例。每个测试用例由一个或多个执行特定测试场景的测试方法组成。 在测试用例类中可以定义 setUptearDown 方法,二者分别在每个测试方法之前和之后运行。

断言用于在测试执行期间验证某些条件是否满足。常见的断言包括 assertEqualassertNotEqualassertTrueassertFalse 等。

tests/test_grep.py:

import os
import shutil
import tempfile
import unittest

from grepy.grep import grep, grep_count, grep_recursive

class TestGrepFunctions(unittest.TestCase):

    def setUp(self):
        # 测试前创建临时目录
        self.test_dir = tempfile.mkdtemp()

    def tearDown(self):
        # 测试后删除临时目录
        shutil.rmtree(self.test_dir)

    def test_grep_single_file(self):
        # 创建测试文件
        test_file_path = os.path.join(self.test_dir, 'test_file.txt')
        with open(test_file_path, 'w') as test_file:
            test_file.write("apple\nbanana\norange\n")

        # 测试 grep 函数处理单个文件
        result = grep('apple', test_file_path)
        self.assertEqual(result, {test_file_path: [(1, 'apple')]})

    def test_grep_ignore_case(self):
        # 创建测试文件
        test_file_path = os.path.join(self.test_dir, 'test_file.txt')
        with open(test_file_path, 'w') as test_file:
            test_file.write("apple\nBanana\norange\n")

        # 测试 grep 函数不区分大小写的处理逻辑
        result = grep('banana', test_file_path, options=['i'])
        self.assertEqual(result, {test_file_path: [(2, 'Banana')]})

    def test_grep_recursive(self):
        # 创建嵌套目录及其文件
        subdir_path = os.path.join(self.test_dir, 'subdir')
        os.makedirs(subdir_path, exist_ok=True)
        file1_path = os.path.join(self.test_dir, 'test_file1.txt')
        file2_path = os.path.join(subdir_path, 'test_file2.txt')
        with open(file1_path, 'w') as file1, open(file2_path, 'w') as file2:
            file1.write("apple\nbanana\norange\n")
            file2.write("apple\nkiwi\nbanana\n")

        # 测试 grep_recursive 函数
        result = grep_recursive('kiwi', self.test_dir)
        expected_result = {file1_path: [], file2_path: [(2, 'kiwi')]}
        self.assertEqual(result, expected_result)

    def test_grep_count(self):
        # 创建测试文件
        test_file1_path = os.path.join(self.test_dir, 'test_file1.txt')
        test_file2_path = os.path.join(self.test_dir, 'test_file2.txt')
        with open(test_file1_path, 'w') as file1, open(test_file2_path, 'w') as file2:
            file1.write("apple\nbanana\norange\n")
            file2.write("apple\nkiwi\nbanana\n")

        # 测试 grep_count 函数
        result = grep_recursive('apple', self.test_dir)
        count = grep_count(result)
        self.assertEqual(count, 2)

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

运行测试用例:

python3 -m unittest tests/test_grep.py

或者,使用 discover 子命令:

cd tests
python3 -m unittest discover

unittest 模块支持测试发现,可自动发现并运行目录或模块下的所有的用例。

应该得到如下结果:

....
----------------------------------------------------------------------
Ran 4 tests in 0.005s

OK

如果遇到错误,你会看到具体的断言报错信息,如下所示:

...F
======================================================================
FAIL: test_grep_single_file (tests.test_grep.TestGrepFunctions)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/projects/lr_grepy/tests/test_grep.py", line 26, in test_grep_single_file
    self.assertEqual(result, {test_file_path: [(1, 'a2pple')]})
AssertionError: {'/va[27 chars]wgzbhddyr40000gn/T/tmp1qd0uxar/test_file.txt': [(1, 'apple')]} != {'/va[27 chars]wgzbhddyr40000gn/T/tmp1qd0uxar/test_file.txt': [(1, 'a2pple')]}
  {'/var/folders/wx/hdjympxj7h3_ntwgzbhddyr40000gn/T/tmp1qd0uxar/test_file.txt': [(1,
-                                                                                  'apple')]}
+                                                                                  'a2pple')]}
?                                                                                    +


----------------------------------------------------------------------
Ran 4 tests in 0.006s

FAILED (failures=1)

然后,你可以根据错误信息修复代码实现中的问题。

上页下页