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

重构多if-else:如何拆分PIN验证逻辑以提升可测试性?

拆分PIN验证逻辑以简化单元测试

你的这段PIN验证代码混合了数据查询、PIN初始化、匹配校验、失败状态更新等多个职责,导致单元测试需要mock仓储、处理复杂分支逻辑,测试成本很高。我们可以按照单一职责原则拆分成多个小方法,每个方法只负责一件事,这样每个部分都能独立测试,无需依赖整个仓储上下文。

拆分核心思路

把业务逻辑判断、计算和仓储操作分离:

  • 纯业务逻辑方法:只接收参数、执行判断/计算,不依赖仓储,方便单独测试
  • 仓储操作方法:专门负责与数据库交互,测试时只需mock这些方法的返回

重构后的代码示例

public async Task<ResultTypes> ValidatePinAsync(int id, string pin)
{
    var customer = await _repository.GetCustomer(id);
    
    // 检查PIN是否已禁用
    if (IsPinDisabled(customer))
        return ResultTypes.PinDisabled;

    // 处理未设置PIN的情况
    if (string.IsNullOrEmpty(customer.PinNumber))
    {
        await InitializeDefaultPin(customer);
        return await HandlePinVerificationResult(customer, pin);
    }

    // 已有PIN的校验逻辑
    return await HandlePinVerificationResult(customer, pin);
}

// 纯逻辑:检查PIN是否禁用
private bool IsPinDisabled(ICustomer customer)
{
    return customer.PinDisabled;
}

// 业务逻辑+仓储操作:初始化默认PIN
private async Task InitializeDefaultPin(ICustomer customer)
{
    customer.PinNumber = customer.DoB.ToString();
    await _repository.UpdateCustomer(customer);
}

// 核心校验逻辑:处理PIN匹配/不匹配的结果
private async Task<ResultTypes> HandlePinVerificationResult(ICustomer customer, string pin)
{
    if (IsPinMatching(customer, pin))
        return ResultTypes.Success;
    
    // 处理验证失败的逻辑
    return await HandlePinVerificationFailure(customer);
}

// 纯逻辑:判断PIN是否匹配
private bool IsPinMatching(ICustomer customer, string pin)
{
    return customer.PinNumber == pin;
}

// 业务逻辑+仓储操作:处理验证失败后的状态更新
private async Task<ResultTypes> HandlePinVerificationFailure(ICustomer customer)
{
    customer.FailureCount++;
    // 判断是否需要禁用PIN(示例:3次失败触发禁用)
    if (customer.FailureCount >= 3)
    {
        customer.PinDisabled = true;
        await _repository.UpdateCustomer(customer);
        return ResultTypes.PinDisabled;
    }
    
    await _repository.UpdateCustomer(customer);
    return ResultTypes.InvalidPinEntered;
}

拆分后的测试优势

  1. 纯逻辑方法可独立测试:比如IsPinMatching、IsPinDisabled,只需传入不同的ICustomer和pin参数,无需mock任何仓储,直接验证返回结果
  2. 仓储依赖方法只需mock交互:比如InitializeDefaultPin,只需验证是否调用了_repository.UpdateCustomer,以及传入的customer是否正确设置了PIN
  3. 分支逻辑更清晰:每个小方法只处理一个分支,测试时可以针对每个分支单独编写用例,覆盖所有场景(比如未设置PIN时的成功/失败、已有PIN的成功/失败、失败次数达上限禁用等)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 04:45:42