每日一题】找出 Flaky 测试用例(附题解代码)

题目:在 CI/CD 流水中,同一个测试用例可能被多次执行。定义"不稳定用例(Flaky Test)"为:在至少 K 次执行中,既出现过 pass 也出现过 fail 的用例。

请实现函数 find_flaky_tests,给定执行记录列表和阈值 K,返回所有 Flaky 用例的 test_id 列表,按字母序排列。

参数说明:

  • results:list[tuple[str, str]],每个元素为 (test_id, status),status 为 "pass" 或 "fail"
  • k:int,最少执行次数阈值,执行次数 < k 的用例不参与判定
def find_flaky_tests(results: list[tuple[str, str]], k: int) -> list[str]:
    """
    找出 flaky 测试用例。

    Args:
        results: 执行记录列表,每个元素为 (test_id, status)
        k: 最少执行次数阈值

    Returns:
        flaky 用例的 test_id 列表(既 pass 过又 fail 过且执行次数 >= k),按字母序排列
    """
    pass


# ---- 断言用例 ----
assert find_flaky_tests([("A","pass"),("A","fail"),("B","pass"),("B","pass")], 2) == ["A"]
assert find_flaky_tests([("A","pass"),("A","fail"),("C","pass")], 2) == ["A"]
assert find_flaky_tests([("D","pass"),("E","fail"),("E","pass"),("E","fail")], 2) == ["E"]
assert find_flaky_tests([], 3) == []
assert find_flaky_tests([("F","pass"),("F","pass"),("G","fail"),("G","fail")], 2) == []
assert find_flaky_tests([("Z","pass"),("Z","fail"),("A","pass"),("A","fail"),("A","pass")], 2) == ["A","Z"]

难度:中级
题型:笔试(编程题)

:point_right:参考答案/题解:

思路一:字典分别计数(暴力直观)

from collections import defaultdict

def find_flaky_tests(results: list[tuple[str, str]], k: int) -> list[str]:
    pass_counts = defaultdict(int)
    fail_counts = defaultdict(int)
    all_tests = set()
    for test_id, status in results:
        all_tests.add(test_id)
        if status == "pass":
            pass_counts[test_id] += 1
        else:
            fail_counts[test_id] += 1
    flaky = [
        tid for tid in all_tests
        if pass_counts[tid] > 0 and fail_counts[tid] > 0
        and (pass_counts[tid] + fail_counts[tid]) >= k
    ]
    return sorted(flaky)

思路二:集合 + 计数器(一行判定核心)

from collections import defaultdict

def find_flaky_tests(results: list[tuple[str, str]], k: int) -> list[str]:
    status_set = defaultdict(set)
    exec_count = defaultdict(int)
    for test_id, status in results:
        status_set[test_id].add(status)
        exec_count[test_id] += 1
    return sorted(
        tid for tid, st in status_set.items()
        if st == {"pass", "fail"} and exec_count[tid] >= k
    )

两种思路时间复杂度均为 O(N + M·logM),N 为记录条数,M 为不同 test_id 数量。

采分点:

  1. 正确理解"至少 K 次执行"的前置过滤条件(执行次数 < k 直接排除)
  2. "既 pass 又 fail"的判定逻辑正确,不能只看最后状态
  3. 返回结果按字母序排列(sorted)
  4. 空输入 / 全稳定 / 多 Flaky 边界用例覆盖
  5. 加分:使用 defaultdict/set 简化逻辑,代码可读性强;能口述复杂度分析