using FsCheck;
using FsCheck.Xunit;
using MiAssessment.Core.Interfaces;
using MiAssessment.Core.Services;
using MiAssessment.Model.Data;
using MiAssessment.Model.Models.Payment;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
namespace MiAssessment.Tests.Services;
///
/// 微信支付版本路由属性测试
/// **Feature: wechat-pay-v3-upgrade**
///
public class WechatPayVersionRoutingPropertyTests
{
#region Property 4: 版本路由正确性
///
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
/// *For any* 支付请求,当商户配置的 PayVersion 为 "V3" 时,应该调用 V3 接口;
/// 当 PayVersion 为 "V2" 时,应该调用 V2 接口。
/// **Validates: Requirements 3.1, 3.5**
///
[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;
}
///
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
/// *For any* 商户配置,PayVersion 只能是 "V2" 或 "V3",默认为 "V2"。
/// **Validates: Requirements 3.1, 3.5**
///
[Fact]
public void PayVersion_DefaultValue_ShouldBeV2()
{
var config = new WechatPayMerchantConfig();
Assert.Equal("V2", config.PayVersion);
}
///
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
/// *For any* V3 配置,必须包含 V3 必要字段才能正确路由。
/// **Validates: Requirements 3.1**
///
[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;
}
///
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
/// *For any* V2 配置,V3 字段可以为空。
/// **Validates: Requirements 3.5**
///
[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);
}
///
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
/// 测试版本路由决策逻辑的正确性。
/// **Validates: Requirements 3.1, 3.5**
///
[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);
}
///
/// **Feature: wechat-pay-v3-upgrade, Property 4: 版本路由正确性**
/// *For any* 订单号前缀,版本路由应该基于商户配置而非订单号。
/// **Validates: Requirements 3.1, 3.5**
///
[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
}