You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编写单元测试调用含argparse参数的方法时触发AttributeError

解决测试count_users时的AttributeError及单元测试优化

错误原因分析

你遇到的AttributeError: 'dict' object has no attribute 'metrics'是因为:

  • 你把argparse的Action对象转换成了字典args,但字典仅支持[]键访问语法,不能用.属性访问(.是面向对象的属性调用方式)
  • 更核心的问题:测试count_users根本不需要构造argparse解析器,这个函数的第二个参数metrics只是一个字符串(输出JSON的路径),而非argparse的Namespace对象。

修正后的测试代码

以下是修复错误并优化后的完整测试代码,包含完整的结果验证逻辑:

import tempfile
import shutil
import unittest
from pyspark.sql import SparkSession, StructType, StructField, DecimalType
from pyspark.sql import functions as F
from decimal import Decimal

# 假设你的业务代码已经导入count_users函数
# from your_module import count_users

class TestUserCount(unittest.TestCase):
    def setUp(self):
        # 初始化SparkSession,放在setUp中复用
        self.spark = SparkSession.builder \
            .master("local[1]") \
            .appName("test_count_users") \
            .getOrCreate()

    def tearDown(self):
        # 测试结束后关闭SparkSession,释放资源
        self.spark.stop()

    def test_count_users(self):
        # 1. 构造测试用的DataFrame
        df = self.spark.createDataFrame(
            data=[
                (Decimal(0),),
                (Decimal(22),),
            ],
            schema=StructType(
                [
                    StructField("users", DecimalType(38, 4), True),
                ]
            ),
        )

        # 2. 创建临时目录用于输出,避免生成垃圾文件
        temp_dir = tempfile.mkdtemp()

        try:
            # 3. 直接调用count_users,传入临时目录作为metrics路径
            count_users(df, temp_dir)

            # 4. 读取生成的JSON文件,验证统计结果是否正确
            result_df = self.spark.read.json(temp_dir)
            user_count = result_df.select("user_count_values").first()[0]
            # 断言:users字段大于0的记录数应为1
            self.assertEqual(user_count, 1)
        finally:
            # 5. 强制清理临时目录,保证测试环境干净
            shutil.rmtree(temp_dir)

关键改进点

  • 移除冗余的argparse代码:直接向count_users传递字符串路径即可,测试无需重复构造命令行解析逻辑
  • 使用临时目录:避免测试后残留无用文件,保证测试独立性
  • 修正验证逻辑:原测试的self.assertTrue(args["metrics"], 1)逻辑完全错误,现在改为验证生成的JSON文件中的统计值是否符合预期
  • 统一管理SparkSession:通过setUp和tearDown方法统一创建和销毁SparkSession,提升测试效率

额外补充

如果你的主逻辑中是通过argparse的Namespace对象传递参数(比如main函数中调用count_users(df, args.metrics)),测试main函数时才需要构造模拟的Namespace对象,示例如下:

def test_main(self):
    temp_dir = tempfile.mkdtemp()
    try:
        # 构造模拟的命令行参数对象
        args = argparse.Namespace(metrics=temp_dir)
        # 调用main函数
        main(args)
        # 验证结果逻辑同test_count_users...
    finally:
        shutil.rmtree(temp_dir)

内容的提问来源于stack exchange,提问作者Mike3355

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 10:01:42