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

Python unittest测试DotaPlayer类时触发FileNotFoundError问题求解

问题原因

  • 第一个错误是FileNotFoundError,根源在logger_create函数的实现:
    1. 日志文件路径依赖当前工作目录(os.getcwd()),直接运行业务代码时工作目录通常是项目根目录,而运行unittest时工作目录默认是tests文件夹,路径计算后指向的位置和预期不符。
    2. logging.FileHandler不会自动创建不存在的父级目录,只要路径中的log文件夹不存在,就会直接抛出找不到文件/目录的错误。
  • 第二个逻辑问题是check_keywords的判断条件写反,你预期的是「缺少三个关键字中的任意一个就抛出SystemExit」,但现有代码的判断是if all(keys in response_json for keys in keywords),也就是三个关键字全部存在时才会进入报错分支,和预期逻辑完全相反,这也是你没拿到预期SystemExit的核心原因之一。

解决方案

第一步:修复日志创建逻辑

修改logger_create函数,自动创建父目录,同时使用固定的项目根目录计算路径,不要依赖动态的工作目录:

import os
import logging

def logger_create():
    logger = logging.getLogger(__name__)
    if not logger.hasHandlers():
        logger.setLevel(logging.INFO)
        formatter = logging.Formatter("%(levelname)s : %(asctime)s :: %(message)s")
        # 先获取当前文件所在目录,再往上找项目根目录,避免依赖os.getcwd()
        current_file_dir = os.path.dirname(os.path.abspath(__file__))
        project_root = os.path.dirname(current_file_dir)
        log_dir = os.path.join(project_root, "log")
        # 自动创建log目录,不存在就新建
        os.makedirs(log_dir, exist_ok=True)
        log_file_path = os.path.join(log_dir, "logger_new.log")
        file_handler = logging.FileHandler(filename=log_file_path)
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)
    return logger

第二步:修复check_keywords的判断逻辑

把all改成not all,符合「只要有一个关键字不存在就报错」的业务逻辑:

@staticmethod
def check_keywords(response_json):
    logger = logger_create()
    keywords = ("kills", "assists", "deaths")
    # 改成not all,判断是否存在缺失的关键字
    if not all(keys in response_json for keys in keywords):
        msg = dict()
        msg["code"] = 2
        msg["message"] = f"Player misses {keywords} for computing the KPI"
        logger.error(msg)
        sys.exit()
    else:
        return response_json

可选:测试时Mock日志避免依赖文件系统

如果不想让单元测试依赖本地目录和文件,可以在测试代码中Mock掉logger_create函数,直接返回模拟的日志对象,跳过文件写入逻辑:

import unittest
from unittest.mock import patch, MagicMock
from analyzer.etl import DotaPlayer

class TestDotaPlayer(unittest.TestCase):
    def setUp(self) -> None:
        self.player = DotaPlayer(3)

    #  mock logger_create,返回模拟的logger
    @patch("analyzer.etl.logger_create")
    def test_check_keywords(self, mock_logger):
        mock_logger.return_value = MagicMock()
        response_json = {
            "match_id": 6135452599,
            "player_slot": 2,
            "duration": 1926,
            "game_mode": 22,
            "lobby_type": 7,
            "hero_id": 129,
            "start_time": 1628968743,
            "skill": 2,
            "leaver_status": 4,
            "party_size": 3,
        }
        with self.assertRaises(SystemExit):
            self.player.check_keywords(response_json)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 23:36:03