188 lines
6.4 KiB
C#
188 lines
6.4 KiB
C#
using FsCheck;
|
||
using FsCheck.Xunit;
|
||
using HoneyBox.Core.Interfaces;
|
||
using HoneyBox.Core.Services;
|
||
using HoneyBox.Model.Data;
|
||
using HoneyBox.Model.Models.Payment;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Logging;
|
||
using Microsoft.Extensions.Options;
|
||
using Moq;
|
||
using Xunit;
|
||
|
||
namespace HoneyBox.Tests.Services;
|
||
|
||
/// <summary>
|
||
/// 微信支付版本路由属性测试
|
||
/// **Feature: wechat-pay-v3-upgrade**
|
||
/// </summary>
|
||
public class WechatPayVersionRoutingPropertyTests
|
||
{
|
||
#region Property 4: 版本路由正确性
|
||
|
||
/// <summary>
|
||
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
|
||
/// *For any* 支付请求,当商户配置的 PayVersion 为 "V3" 时,应该调用 V3 接口;
|
||
/// 当 PayVersion 为 "V2" 时,应该调用 V2 接口。
|
||
/// **Validates: Requirements 3.1, 3.5**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool VersionRouting_ShouldRouteToCorrectService_BasedOnPayVersion(
|
||
NonEmptyString orderNo,
|
||
PositiveInt userId,
|
||
PositiveInt amount,
|
||
bool isV3)
|
||
{
|
||
// Arrange
|
||
var payVersion = isV3 ? "V3" : "V2";
|
||
// 安全地处理订单号,确保不会越界
|
||
var cleanOrderNo = orderNo.Get.Replace("-", "");
|
||
var orderNoStr = $"MYH{(cleanOrderNo.Length > 10 ? cleanOrderNo.Substring(0, 10) : cleanOrderNo)}";
|
||
|
||
var merchantConfig = new WechatPayMerchantConfig
|
||
{
|
||
Name = "测试商户",
|
||
MchId = "1738725801",
|
||
AppId = "wx1234567890",
|
||
Key = "testkey123456789012345678901234",
|
||
OrderPrefix = "MYH",
|
||
PayVersion = payVersion,
|
||
ApiV3Key = isV3 ? "d1cxc0vXCUH2984901DxddPJMYqcwcnd" : null,
|
||
CertSerialNo = isV3 ? "SERIAL123456" : null,
|
||
PrivateKeyPath = isV3 ? "certs/test/key.pem" : null,
|
||
WechatPublicKeyId = isV3 ? "PUBKEYID123" : null,
|
||
WechatPublicKeyPath = isV3 ? "certs/test/pub.pem" : null,
|
||
NotifyUrl = "https://example.com/notify"
|
||
};
|
||
|
||
// 验证版本路由逻辑
|
||
var shouldUseV3 = merchantConfig.PayVersion == "V3";
|
||
|
||
// 属性:PayVersion 为 "V3" 时应该路由到 V3,否则路由到 V2
|
||
return shouldUseV3 == isV3;
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
|
||
/// *For any* 商户配置,PayVersion 只能是 "V2" 或 "V3",默认为 "V2"。
|
||
/// **Validates: Requirements 3.1, 3.5**
|
||
/// </summary>
|
||
[Fact]
|
||
public void PayVersion_DefaultValue_ShouldBeV2()
|
||
{
|
||
var config = new WechatPayMerchantConfig();
|
||
Assert.Equal("V2", config.PayVersion);
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
|
||
/// *For any* V3 配置,必须包含 V3 必要字段才能正确路由。
|
||
/// **Validates: Requirements 3.1**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool V3Config_ShouldHaveRequiredFields_WhenPayVersionIsV3(
|
||
NonEmptyString apiV3Key,
|
||
NonEmptyString certSerialNo,
|
||
NonEmptyString privateKeyPath)
|
||
{
|
||
var config = new WechatPayMerchantConfig
|
||
{
|
||
PayVersion = "V3",
|
||
ApiV3Key = apiV3Key.Get,
|
||
CertSerialNo = certSerialNo.Get,
|
||
PrivateKeyPath = privateKeyPath.Get
|
||
};
|
||
|
||
// V3 配置必须有这些字段
|
||
var hasRequiredFields = !string.IsNullOrEmpty(config.ApiV3Key) &&
|
||
!string.IsNullOrEmpty(config.CertSerialNo) &&
|
||
!string.IsNullOrEmpty(config.PrivateKeyPath);
|
||
|
||
return config.PayVersion == "V3" && hasRequiredFields;
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
|
||
/// *For any* V2 配置,V3 字段可以为空。
|
||
/// **Validates: Requirements 3.5**
|
||
/// </summary>
|
||
[Fact]
|
||
public void V2Config_ShouldWorkWithoutV3Fields()
|
||
{
|
||
var config = new WechatPayMerchantConfig
|
||
{
|
||
Name = "V2商户",
|
||
MchId = "1234567890",
|
||
AppId = "wx1234567890",
|
||
Key = "v2key12345678901234567890123456",
|
||
PayVersion = "V2",
|
||
// V3 字段为空
|
||
ApiV3Key = null,
|
||
CertSerialNo = null,
|
||
PrivateKeyPath = null
|
||
};
|
||
|
||
// V2 配置不需要 V3 字段
|
||
Assert.Equal("V2", config.PayVersion);
|
||
Assert.Null(config.ApiV3Key);
|
||
Assert.Null(config.CertSerialNo);
|
||
Assert.Null(config.PrivateKeyPath);
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
|
||
/// 测试版本路由决策逻辑的正确性。
|
||
/// **Validates: Requirements 3.1, 3.5**
|
||
/// </summary>
|
||
[Theory]
|
||
[InlineData("V3", true)]
|
||
[InlineData("V2", false)]
|
||
[InlineData("v3", false)] // 大小写敏感
|
||
[InlineData("v2", false)] // 大小写敏感
|
||
[InlineData("", false)]
|
||
[InlineData(null, false)]
|
||
public void VersionRouting_Decision_ShouldBeCorrect(string? payVersion, bool expectedV3Route)
|
||
{
|
||
// 版本路由决策逻辑
|
||
var shouldRouteToV3 = payVersion == "V3";
|
||
|
||
Assert.Equal(expectedV3Route, shouldRouteToV3);
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
|
||
/// *For any* 订单号前缀,版本路由应该基于商户配置而非订单号。
|
||
/// **Validates: Requirements 3.1, 3.5**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool VersionRouting_ShouldBeBasedOnMerchantConfig_NotOrderNo(
|
||
NonEmptyString orderPrefix,
|
||
bool isV3)
|
||
{
|
||
// 安全地处理订单前缀
|
||
var prefix = orderPrefix.Get.Length >= 3 ? orderPrefix.Get.Substring(0, 3) : orderPrefix.Get.PadRight(3, 'X');
|
||
|
||
// 创建两个商户配置,一个 V2,一个 V3
|
||
var v2Config = new WechatPayMerchantConfig
|
||
{
|
||
OrderPrefix = prefix,
|
||
PayVersion = "V2"
|
||
};
|
||
|
||
var v3Config = new WechatPayMerchantConfig
|
||
{
|
||
OrderPrefix = prefix,
|
||
PayVersion = "V3"
|
||
};
|
||
|
||
// 相同的订单前缀,不同的版本配置
|
||
// 版本路由应该基于 PayVersion 字段
|
||
var v2ShouldRouteToV3 = v2Config.PayVersion == "V3";
|
||
var v3ShouldRouteToV3 = v3Config.PayVersion == "V3";
|
||
|
||
return !v2ShouldRouteToV3 && v3ShouldRouteToV3;
|
||
}
|
||
|
||
#endregion
|
||
}
|