feat(tenpayv3): 升级公共组件

This commit is contained in:
Fu Diwei 2022-01-21 13:10:56 +08:00
parent 3656eb176f
commit b442a3d618
48 changed files with 304 additions and 569 deletions

View File

@ -1,61 +0,0 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Linq;
namespace Newtonsoft.Json.Converters
{
internal class TextualStringIListWithCommaConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
bool ret = objectType == typeof(IList<string>) || objectType == typeof(List<string>);
if (!ret)
{
ret = objectType.IsGenericType &&
objectType.GetGenericTypeDefinition() == typeof(List<>) &&
objectType.GetElementType() == typeof(string);
}
return ret;
}
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
else if (reader.TokenType == JsonToken.String)
{
string? value = serializer.Deserialize<string>(reader);
if (value == null)
return null;
if (string.IsNullOrEmpty(value))
return new List<string>();
return value.Split(',').ToList();
}
throw new JsonReaderException();
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value != null)
writer.WriteValue(string.Join(",", value));
else
writer.WriteNull();
}
}
}

View File

@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Newtonsoft.Json.Converters
{
internal class TextualStringIListWithJsonConverter : JsonConverter<IList<string>?>
{
private readonly JsonConverter<List<string>?> _converter = new TextualStringListWithJsonConverter();
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override IList<string>? ReadJson(JsonReader reader, Type objectType, IList<string>? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return _converter.ReadJson(reader, objectType, ConvertIListToList(existingValue), hasExistingValue, serializer);
}
public override void WriteJson(JsonWriter writer, IList<string>? value, JsonSerializer serializer)
{
_converter.WriteJson(writer, ConvertIListToList(value), serializer);
}
private List<string>? ConvertIListToList(IList<string>? src)
{
if (src == null)
return null;
List<string>? dest = src as List<string>;
if (dest != null)
return dest;
return new List<string>(src);
}
}
}

View File

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Newtonsoft.Json.Converters
{
internal class TextualStringListWithCommaConverter : JsonConverter<List<string>?>
{
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override List<string>? ReadJson(JsonReader reader, Type objectType, List<string>? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
else if (reader.TokenType == JsonToken.String)
{
string? value = serializer.Deserialize<string>(reader);
if (value == null)
return existingValue;
return value.Split(',').ToList();
}
throw new JsonReaderException();
}
public override void WriteJson(JsonWriter writer, List<string>? value, JsonSerializer serializer)
{
if (value != null)
writer.WriteValue(string.Join(",", value));
else
writer.WriteNull();
}
}
}

View File

@ -1,46 +0,0 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Newtonsoft.Json.Converters
{
internal class TextualStringListWithJsonConverter : JsonConverter<List<string>?>
{
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override List<string>? ReadJson(JsonReader reader, Type objectType, List<string>? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
else if (reader.TokenType == JsonToken.String)
{
string? value = serializer.Deserialize<string>(reader);
if (value == null)
return existingValue;
return JsonConvert.DeserializeObject<List<string>>(value);
}
throw new JsonReaderException();
}
public override void WriteJson(JsonWriter writer, List<string>? value, JsonSerializer serializer)
{
if (value != null)
writer.WriteValue(JsonConvert.SerializeObject(value, Formatting.None));
else
writer.WriteNull();
}
}
}

View File

@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace System.Text.Json.Converters
{
internal class TextualStringIListWithCommaConverter : JsonConverter<List<string>?>
{
public override List<string>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
else if (reader.TokenType == JsonTokenType.String)
{
string? value = reader.GetString();
if (value == null)
return null;
return value.Split(',').ToList();
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, List<string>? value, JsonSerializerOptions options)
{
if (value != null)
writer.WriteStringValue(string.Join(",", value));
else
writer.WriteNullValue();
}
}
}

View File

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace System.Text.Json.Converters
{
internal class TextualStringIListWithJsonConverter : JsonConverter<IList<string>?>
{
private readonly JsonConverter<List<string>?> _converter = new TextualStringListWithJsonConverter();
public override IList<string>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return _converter.Read(ref reader, typeToConvert, options);
}
public override void Write(Utf8JsonWriter writer, IList<string>? value, JsonSerializerOptions options)
{
_converter.Write(writer, ConvertIListToList(value), options);
}
private List<string>? ConvertIListToList(IList<string>? src)
{
if (src == null)
return null;
List<string>? dest = src as List<string>;
if (dest != null)
return dest;
return new List<string>(src);
}
}
}

View File

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace System.Text.Json.Converters
{
internal class TextualStringListWithCommaConverter : JsonConverter<IList<string>?>
{
private readonly JsonConverter<List<string>?> _converter = new TextualStringIListWithCommaConverter();
public override IList<string>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return _converter.Read(ref reader, typeToConvert, options);
}
public override void Write(Utf8JsonWriter writer, IList<string>? value, JsonSerializerOptions options)
{
_converter.Write(writer, ConvertIListToList(value), options);
}
private List<string>? ConvertIListToList(IList<string>? src)
{
if (src == null)
return null;
List<string>? dest = src as List<string>;
if (dest != null)
return dest;
return new List<string>(src);
}
}
}

View File

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace System.Text.Json.Converters
{
internal class TextualStringListWithJsonConverter : JsonConverter<List<string>?>
{
public override List<string>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
else if (reader.TokenType == JsonTokenType.String)
{
string? value = reader.GetString();
if (value == null)
return null;
return JsonSerializer.Deserialize<List<string>>(value, options);
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, List<string>? value, JsonSerializerOptions options)
{
if (value != null)
writer.WriteStringValue(JsonSerializer.Serialize(value, options));
else
writer.WriteNullValue();
}
}
}

View File

@ -692,9 +692,9 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
/// 获取或设置优惠费率活动值。
/// </summary>
[Newtonsoft.Json.JsonProperty("activities_rate")]
[Newtonsoft.Json.JsonConverter(typeof(Converters.NewtonsoftJsonActivityRateConverter))]
[Newtonsoft.Json.JsonConverter(typeof(Converters.RequestPropertyActivityRateNewtonsoftJsonConverter))]
[System.Text.Json.Serialization.JsonPropertyName("activities_rate")]
[System.Text.Json.Serialization.JsonConverter(typeof(Converters.SystemTextJsonActivityRateConverter))]
[System.Text.Json.Serialization.JsonConverter(typeof(Converters.RequestPropertyActivityRateSystemTextJsonConverter))]
public double? ActivityRate { get; set; }
/// <summary>
@ -793,7 +793,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
internal static class Converters
{
internal class NewtonsoftJsonActivityRateConverter : Newtonsoft.Json.JsonConverter<double?>
internal class RequestPropertyActivityRateNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter<double?>
{
public override bool CanRead
{
@ -837,7 +837,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
}
}
internal class SystemTextJsonActivityRateConverter : System.Text.Json.Serialization.JsonConverter<double?>
internal class RequestPropertyActivityRateSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter<double?>
{
public override double? Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
{

View File

@ -280,6 +280,17 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
}
}
internal static class Converters
{
public class RequestPropertyMediaIdListNewtonsoftJsonConverter : Newtonsoft.Json.Converters.TextualObjectInJsonFormatConverterBase<IList<string>>
{
}
public class RequestPropertyMediaIdListSystemTextJsonConverter : System.Text.Json.Converters.TextualObjectInJsonFormatConverterBase<IList<string>>
{
}
}
/// <summary>
/// 获取或设置业务申请编号。
/// </summary>
@ -368,18 +379,18 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
/// 获取或设置特殊资质图片媒体文件标识 ID 列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("qualifications")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.TextualStringIListWithJsonConverter))]
[Newtonsoft.Json.JsonConverter(typeof(Converters.RequestPropertyMediaIdListNewtonsoftJsonConverter))]
[System.Text.Json.Serialization.JsonPropertyName("qualifications")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.TextualStringIListWithJsonConverter))]
[System.Text.Json.Serialization.JsonConverter(typeof(Converters.RequestPropertyMediaIdListSystemTextJsonConverter))]
public IList<string>? QualificationPictureMediaIdList { get; set; }
/// <summary>
/// 获取或设置补充材料媒体文件标识 ID 列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("business_addition_pics")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.TextualStringIListWithJsonConverter))]
[Newtonsoft.Json.JsonConverter(typeof(Converters.RequestPropertyMediaIdListNewtonsoftJsonConverter))]
[System.Text.Json.Serialization.JsonPropertyName("business_addition_pics")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.TextualStringIListWithJsonConverter))]
[System.Text.Json.Serialization.JsonConverter(typeof(Converters.RequestPropertyMediaIdListSystemTextJsonConverter))]
public IList<string>? BusinessAdditionPictureMediaIdList { get; set; }
/// <summary>

View File

@ -0,0 +1,27 @@
## SKIT.FlurlHttpClient.Wechat.TenpayV3
[![GitHub Stars](https://img.shields.io/github/stars/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat?logo=github&label=Stars)](https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat) [![GitHub Forks](https://img.shields.io/github/forks/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat?logo=github&label=Forks)](https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat) [![NuGet Download](https://img.shields.io/nuget/dt/SKIT.FlurlHttpClient.Wechat.TenpayV3.svg?sanitize=true&label=Downloads)](https://www.nuget.org/packages/SKIT.FlurlHttpClient.Wechat.TenpayV3) [![License](https://img.shields.io/github/license/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat?label=License)](https://mit-license.org/)
基于 `Flurl.Http` 的微信商户平台 API v3 版客户端。
---
### 【功能特性】
- 基于微信支付 v3 版 API 封装。
- 支持直连商户、服务商两种模式。
- 请求时自动生成签名,无需开发者手动干预。
- 提供了微信支付所需的 RSA、AES、SHA-256 等算法工具类。
- 提供了调起支付签名、解析响应敏感数据、解析回调通知事件敏感数据等扩展方法。
---
### 【开发文档】
[点此查看](https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat)。
---
### 【更新日志】
[点此查看](https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat/blob/main/CHANGELOG.md)。

View File

@ -9,6 +9,8 @@
<PropertyGroup>
<PackageId>SKIT.FlurlHttpClient.Wechat.TenpayV3</PackageId>
<PackageIcon>LOGO.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat</PackageProjectUrl>
<PackageTags>Flurl.Http Wechat Weixin MicroMessage Tenpay WechatPay WeixinPay Wxpay 微信 微信支付 微信商户</PackageTags>
@ -17,11 +19,22 @@
<Authors>Fu Diwei</Authors>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
<Deterministic>true</Deterministic>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<None Include="../../LOGO.png" Pack="true" PackagePath="/" />
<None Include="README.md" Pack="true" PackagePath="/" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Web" Condition="'$(TargetFramework)' == 'net461' Or '$(TargetFramework)' == 'net47'" />
</ItemGroup>
@ -29,7 +42,7 @@
<ItemGroup>
<PackageReference Include="System.ValueTuple" Version="4.5.0" Condition="'$(TargetFramework)' == 'net461'" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="SKIT.FlurlHttpClient.Common" Version="2.1.1" />
<PackageReference Include="SKIT.FlurlHttpClient.Common" Version="2.2.0" />
</ItemGroup>
</Project>

View File

@ -10,7 +10,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
public static class SHA256Utility
{
/// <summary>
/// 获取信息摘要。
/// 获取 SHA-256 信息摘要。
/// </summary>
/// <param name="bytes">信息字节数组。</param>
/// <returns>信息摘要。</returns>
@ -24,7 +24,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
}
/// <summary>
/// 获取信息摘要。
/// 获取 SHA-256 信息摘要。
/// </summary>
/// <param name="message">文本信息。</param>
/// <returns>信息摘要。</returns>

View File

@ -4,7 +4,7 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests
{
public class TestCase_JsonConverterTest
public class TestCase_JsonConverterTests
{
[Fact(DisplayName = "测试用例:自定义转换器之 `FlattenNArrayObjectConverterBase`")]
public void TestFlattenNArrayObjectConverter()

View File

@ -13,8 +13,7 @@
"transfer_amount": 200000,
"transfer_remark": "2020年4月报销",
"openid": "o-MYE42l80oelYMDE34nYD456Xoy",
"user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
"user_id_card": "8609cb22e1774a50a930e414cc71eca06121bcd266335cda230d24a7886a8d9f"
"user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45"
}
],
"sp_appid": "wxf636efh567hg4388",

View File

@ -11,8 +11,7 @@
"transfer_amount": 200000,
"transfer_remark": "2020年4月报销",
"openid": "o-MYE42l80oelYMDE34nYD456Xoy",
"user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
"user_id_card": "8609cb22e1774a50a930e414cc71eca06121bcd266335cda230d24a7886a8d9f"
"user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45"
}
]
}

View File

@ -1,8 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1; net6.0</TargetFrameworks>
<LangVersion>9.0</LangVersion>
<TargetFrameworks>net472; netcoreapp3.1; net6.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<NullableReferenceTypes>true</NullableReferenceTypes>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class TestCase_AesUtilityTests
{
[Fact(DisplayName = "测试用例AES-GCM 解密")]
public void TestAESGCMDecrypt()
{
string key = "f09b03a7a1902b5b4913856f1fd07ab1";
string iv = "aae8c2e79c5b";
string aad = "certificate";
string cipherText = "x9kkL5w1JuaypcjhrYIP+kVNlN8o8uN4yJyJjy5lg+PyPnQL2Zn//ORaXAyzdaK/WBMVd3u/Y9hLaTBLMyRXzowsrkJ5PT37johye48N7BAJQ0PJwW++d1RdhOOPjoqfmws6rSV5Gv2qhfdKjmpxVjr8xr71dtBt8J2wu+bAV99HHQoAynm/Pp9OQYZgpOQ+1cyFHd43TAxOoFfmixKrXr3HP8lJot0XCUSq4qkr1Hs44FV2KuzntSk8eqKr5N17UcuPF3VYnnnF/AvQ7HuLKWwrHhUbaXfkwy0Q2n36UJMfBj7344S97E8BnS89ojgOPQi+olBPyNgrtDWHgsJAKu7HA6PV/FgmXcrZirje/AH1u25es4z5xItHscm//6rDvALgf7greV5OJzMsSl/KVDtbkjDSzim0j4ZTduIfzh7l6jfOz115ITcNILT9ef2KkcMyBBc89GZlMGeHTbgsBHzGeLawX3dXFjqt5aMnHM3VWCovA2aUM4c//rqkZGf+Va86OEFoJQLiSTFpkOrKxcIxcrbKPLTgiDWRT3wzmnUDg7kSPbluzt3ROvMFq9lB8bO/pBd7TD2w87sfUdKLj69FniX6s37SBeRVhw8GSIvBf5lpLUhqL5zKYlbuAWePuz0wVV4NTtkaVKZlmm8KTODyZDFpsyKPubDDcwT1ftRf5aSVM4x04I/1B7GkNz/TOy+zpJ0h0B7VHdxyO5JYiI/1qsatX/FE2aJdQYMYOtqfDH7ZH5UUKIqo538OKvE2M4MlBR/aVE4z4QDKfE/1kYrOfvVGfDzF/FWHfUrcqB8kdQMvk8vCoM8yYZsX4KE1aoJbNM2pWv2tpr9JE8b/VQgUyHOgPYAha+UOmZki4Sfl9H62687EIWdbM57ZxmwIiBp60SrJLiBfZon9JqXKdtJOKj0CRokQiBnONNXCVerLFeBNQfeKRw8tgJXf+QPohMGYkSDdc8hTgdbmhTwB1Vv01stlYK12QMNRCovlp/fcmpB72Phlq+/3p5pqMzknw+qm5QAz7JnpZJCFHit52gHwAkKRkVPB3HF2rfLrdTYz5c9Bok1ICAY9My47eLFdduIe99V52cjMLQuUmNFBPrDdyZKVqIHJ/wtWO/wIFpAVGSJMHctyEKmeJVc1IQN74Wm00PrpPackHdO3G41bBmkp5pqUdsSgSkwdfNVqv0cMcSe04NrRGNKMcZ7TA/CMaP1YnhxvVE+z8aksJqSJ+gdplvuwl40y5C8UEHeAi1V8Q0Bf4YvYRgOVIWm2Lzjdn2z9PWLGcStUj11/1hthk2li4V3mgm2Cr2IZme2sn4rZmJ6dexGP1nk+ZYOq0xLE8F7oex9gyDN+A/6zHqnuhO/X08qye0gochMr8U89Qvj2c0L3P2mjCea2H1mEriAJPqMPMKIinh1lQJEZufnfCcPxbZLKTtl6zHtHgOztejd1gV/nUyCVKD4MCMfBDy9C/Af8pWx6akOg/QSQNIGA2AI6zprHn9zEjpFIzXJYvruVI22Yt6oF9Xnt7Ki82wRK2M96r4kj6cwSs4exMPGv8fWMrFTm0Br6p6T+HZsxyyn2ChuPIgpfisnce/ZaU/0xCZhK/K79+TK2GeeChq5oEpua/1tx4+kDHi7H9381pLJmy2oXW060c2mmwA9+EpcuwEDhr8fsnghbv41u7b1NhEmWNVUy29Dwaz61PPGUdh5DsvaKLWC+raZ/6UEKPw+tiABJ5o6u2jAWgmEYmmJCKapNgtfPc6D+O0aHH9oqh6u4+8NRAhusPZzDGWBr6AT4pexgWFeEhZhn6bXM9HhpUe0IhOTw5D+tqXrTlNon4kjYibiMUFy1h2YyYS3IEdu1J4xqvo0rFyCxF1C+P6ubc0tClRPkXg==";
string actualPlain = Utilities.AESUtility.DecryptWithGCM(key: key, iv: iv, aad: aad, cipherText: cipherText);
string expectedPlain = "-----BEGIN CERTIFICATE-----\nMIID3DCCAsSgAwIBAgIUGZNrTcamx3sFSJsQli3v9C6gZe8wDQYJKoZIhvcNAQEL\nBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\nFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\nQ0EwHhcNMjAwODAxMDczNTE4WhcNMjUwNzMxMDczNTE4WjBuMRgwFgYDVQQDDA9U\nZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl\nbnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo\nZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOAYHqxCqaRzoTIvgV\nixaYJJvmvHbiczbx5MQ9XL1ITSFxkTsNsk7RKHnO7eBS5imheJgQwd22Ky+XclSe\n7B4odssu/l/+gHo2gooTYrrCpQrOkpvGMf8R8aI56BQIF+vsomDvVq1NojHV2Fql\njMwFXzhj2EmU6p6gDv9iL7q1NrfnxFx8iJe4OhIB5Ek4qn1xXxrTUhiULd2vXlbI\nXhRetZSNcJsLt5Rw7D7c8F+aX2JchfeqsZECwKW7bSjMbVWWC6M9MgkB/aId8P0y\n7qEiiXFJkfkg1I/E1ud2apopsid5tdCyRRR6+MhhX2EC8S04MN4soUT7haqNNxX2\nrKHnAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBc\nMFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3Js\nP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJ\nKoZIhvcNAQELBQADggEBAJyg2z4oLQmPfftLQWyzbUc9ONhRMtfA+tVlVBgtLLKn\nWuDlsmEntheM07fu84F4pcfs3yHzjD7pAOFbO4Yt1yhQ50DK35sjbRWepPdWJZLl\nni7KBctcmm0o4zq37oB7vonmBEbFqYs9DaINYOjgI3J25iSBkPVC7dBbvFj2xB0L\ncIcXipq30tDdC/oUem27MNzwZAt49WthKhw6u3HSkcE5cO4LyYTsJhSyG/7LXwvV\nMgX4Jyzo0SSiGOU1/beaZssTVI8sTPJVlHWjhNE3Lc2SaAlKGfGwvt0X3cEZEF+7\noEZIFTkkAF2JhqfnpR3gST0G8Umq1SaVtCPP/zVI8x0=\n-----END CERTIFICATE-----";
Assert.Equal(expectedPlain, actualPlain);
}
}
}

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteBillTests
public class TestCase_ApiExecuteExecuteBillTests
{
[Fact(DisplayName = "[GET] /bill/tradebill")]
public async Task GetBillTradeBillTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /bill/tradebill")]
public async Task TestExecuteGetBillTradeBill()
{
var request = new Models.GetBillTradeBillRequest()
{
@ -24,8 +24,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.DownloadUrl);
}
[Fact(DisplayName = "[GET] /bill/fundflowbill")]
public async Task GetBillFundflowBillTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /bill/fundflowbill")]
public async Task TestExecuteGetBillFundflowBill()
{
var request = new Models.GetBillFundflowBillRequest()
{
@ -39,8 +39,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.DownloadUrl);
}
[Fact(DisplayName = "[GET] /billdownload/file")]
public async Task DownloadBillFileTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /billdownload/file")]
public async Task TestExecuteDownloadBillFile()
{
var request = new Models.DownloadBillFileRequest()
{

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteCombineTransactionsTests
public class TestCase_ApiExecuteExecuteCombineTransactionsTests
{
[Fact(DisplayName = "[POST] /combine-transactions/app")]
public async Task CreateCombineTransactionAppTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /combine-transactions/app")]
public async Task TestExecuteCreateCombineTransactionApp()
{
var request = new Models.CreateCombineTransactionAppRequest()
{
@ -35,8 +35,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.PrepayId);
}
[Fact(DisplayName = "[POST] /combine-transactions/jsapi")]
public async Task CreateCombineTransactionJsapiTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /combine-transactions/jsapi")]
public async Task TestExecuteCreateCombineTransactionJsapi()
{
var request = new Models.CreateCombineTransactionJsapiRequest()
{
@ -74,8 +74,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.PrepayId);
}
[Fact(DisplayName = "[POST] /combine-transactions/h5")]
public async Task CreateCombineTransactionH5Test()
[Fact(DisplayName = "测试用例:调用 API [POST] /combine-transactions/h5")]
public async Task TestExecuteCreateCombineTransactionH5()
{
var request = new Models.CreateCombineTransactionH5Request()
{
@ -100,8 +100,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.H5Url);
}
[Fact(DisplayName = "[POST] /combine-transactions/native")]
public async Task CreateCombineTransactionNativeTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /combine-transactions/native")]
public async Task TestExecuteCreateCombineTransactionNative()
{
var request = new Models.CreateCombineTransactionNativeRequest()
{
@ -126,8 +126,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.QrcodeUrl);
}
[Fact(DisplayName = "[GET] /combine-transactions/out-trade-no/{combine_out_trade_no}")]
public async Task GetCombineTransactionByCombineOutTradeNumberTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /combine-transactions/out-trade-no/{combine_out_trade_no}")]
public async Task TestExecuteGetCombineTransactionByCombineOutTradeNumber()
{
var request = new Models.GetCombineTransactionByCombineOutTradeNumberRequest()
{
@ -141,8 +141,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotEmpty(response.SubOrderList);
}
[Fact(DisplayName = "[POST] /combine-transactions/out-trade-no/{combine_out_trade_no}/close")]
public async Task CloseCombineTransactionTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /combine-transactions/out-trade-no/{combine_out_trade_no}/close")]
public async Task TestExecuteCloseCombineTransaction()
{
var request = new Models.CloseCombineTransactionRequest()
{

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteMarketingBusifavorTests
public class TestCase_ApiExecuteExecuteMarketingBusifavorTests
{
[Fact(DisplayName = "[POST] /marketing/busifavor/stocks")]
public async Task CreateMarketingBusifavorStockTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /marketing/busifavor/stocks")]
public async Task TestExecuteCreateMarketingBusifavorStock()
{
var request = new Models.CreateMarketingBusifavorStockRequest()
{
@ -45,8 +45,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.StockId);
}
[Fact(DisplayName = "[GET] /marketing/busifavor/stocks/{stock_id}")]
public async Task GetMarketingBusifavorStockByStockIdTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /marketing/busifavor/stocks/{stock_id}")]
public async Task TestExecuteGetMarketingBusifavorStockByStockId()
{
var request = new Models.GetMarketingBusifavorStockByStockIdRequest()
{
@ -64,8 +64,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.CouponCodeMode);
}
[Fact(DisplayName = "[GET] /marketing/busifavor/users/{openid}/coupons")]
public async Task QueryMarketingBusifavorUserCouponsTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /marketing/busifavor/users/{openid}/coupons")]
public async Task TestExecuteQueryMarketingBusifavorUserCoupons()
{
var request = new Models.QueryMarketingBusifavorUserCouponsRequest()
{
@ -78,8 +78,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.True(response.IsSuccessful());
}
[Fact(DisplayName = "[POST] /marketing/busifavor/callbacks")]
public async Task UpdateMarketingBusifavorCallbackTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /marketing/busifavor/callbacks")]
public async Task TestExecuteUpdateMarketingBusifavorCallback()
{
var request = new Models.UpdateMarketingBusifavorCallbackRequest()
{
@ -91,8 +91,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.NotifyUrl);
}
[Fact(DisplayName = "[GET] /marketing/busifavor/callbacks")]
public async Task GetMarketingBusifavorCallbackTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /marketing/busifavor/callbacks")]
public async Task TestExecuteGetMarketingBusifavorCallback()
{
var request = new Models.GetMarketingBusifavorCallbackRequest();
var response = await TestClients.Instance.ExecuteGetMarketingBusifavorCallbackAsync(request);

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteMarketingFavorTests
public class TestCase_ApiExecuteExecuteMarketingFavorTests
{
[Fact(DisplayName = "[POST] /marketing/favor/coupon-stocks")]
public async Task CreateMarketingFavorStockTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /marketing/favor/coupon-stocks")]
public async Task TestExecuteCreateMarketingFavorStock()
{
var request = new Models.CreateMarketingFavorStockRequest()
{
@ -42,8 +42,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.StockId);
}
[Fact(DisplayName = "[POST] /marketing/favor/stocks/{stock_id}/start")]
public async Task StartMarketingFavorStockTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /marketing/favor/stocks/{stock_id}/start")]
public async Task TestExecuteStartMarketingFavorStock()
{
var request = new Models.StartMarketingFavorStockRequest()
{
@ -55,8 +55,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.StockId);
}
[Fact(DisplayName = "[POST] /marketing/favor/stocks/{stock_id}/pause")]
public async Task PauseMarketingFavorStockTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /marketing/favor/stocks/{stock_id}/pause")]
public async Task TestExecutePauseMarketingFavorStock()
{
var request = new Models.PauseMarketingFavorStockRequest()
{
@ -68,8 +68,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.StockId);
}
[Fact(DisplayName = "[POST] /marketing/favor/stocks/{stock_id}/restart")]
public async Task RestartMarketingFavorStockTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /marketing/favor/stocks/{stock_id}/restart")]
public async Task TestExecuteRestartMarketingFavorStock()
{
var request = new Models.RestartMarketingFavorStockRequest()
{
@ -81,8 +81,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.StockId);
}
[Fact(DisplayName = "[GET] /marketing/favor/stocks/{stock_id}")]
public async Task GetMarketingFavorStockByStockIdTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /marketing/favor/stocks/{stock_id}")]
public async Task TestExecuteGetMarketingFavorStockByStockId()
{
var request = new Models.GetMarketingFavorStockByStockIdRequest()
{
@ -94,8 +94,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.StockId);
}
[Fact(DisplayName = "[GET] /marketing/favor/stocks")]
public async Task QueryMarketingFavorStocksTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /marketing/favor/stocks")]
public async Task TestExecuteQueryMarketingFavorStocks()
{
var request = new Models.QueryMarketingFavorStocksRequest();
var response = await TestClients.Instance.ExecuteQueryMarketingFavorStocksAsync(request);
@ -113,8 +113,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
}
}
[Fact(DisplayName = "[GET] /marketing/favor/stocks/{stock_id}/merchants")]
public async Task QueryMarketingFavorStockMerchantsTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /marketing/favor/stocks/{stock_id}/merchants")]
public async Task TestExecuteQueryMarketingFavorStockMerchants()
{
var request = new Models.QueryMarketingFavorStockMerchantsRequest()
{
@ -127,8 +127,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.MerchantIdList);
}
[Fact(DisplayName = "[GET] /marketing/favor/stocks/{stock_id}/items")]
public async Task QueryMarketingFavorStockItemsTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /marketing/favor/stocks/{stock_id}/items")]
public async Task TestExecuteQueryMarketingFavorStockItems()
{
var request = new Models.QueryMarketingFavorStockItemsRequest()
{
@ -141,8 +141,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.Items);
}
[Fact(DisplayName = "[POST] /marketing/favor/callbacks")]
public async Task UpdateMarketingFavorCallbackTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /marketing/favor/callbacks")]
public async Task TestExecuteUpdateMarketingFavorCallback()
{
var request = new Models.UpdateMarketingFavorCallbackRequest()
{

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteMarketingMediaTests
public class TestCase_ApiExecuteExecuteMarketingMediaTests
{
[Fact(DisplayName = "[POST] /marketing/favor/media/image-upload")]
public async Task UploadMarketingMediaImageTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /marketing/favor/media/image-upload")]
public async Task TestExecuteUploadMarketingMediaImage()
{
var request = new Models.UploadMarketingMediaImageRequest()
{

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteMarketingPartnershipsTests
public class TestCase_ApiExecuteExecuteMarketingPartnershipsTests
{
[Fact(DisplayName = "[POST] /marketing/partnerships/build")]
public async Task BuildMarketingPartnershipTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /marketing/partnerships/build")]
public async Task TestExecuteBuildMarketingPartnership()
{
var request = new Models.BuildMarketingPartnershipRequest()
{
@ -30,8 +30,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.State);
}
[Fact(DisplayName = "[GET] /marketing/partnerships")]
public async Task QueryMarketingPartnershipsTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /marketing/partnerships")]
public async Task TestExecuteQueryMarketingPartnerships()
{
var request = new Models.QueryMarketingPartnershipsRequest()
{

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteMarketingPayGiftActivityTests
public class TestCase_ApiExecuteExecuteMarketingPayGiftActivityTests
{
[Fact(DisplayName = "[GET] /marketing/paygiftactivity/activities")]
public async Task QueryMarketingPayGiftActivitiesTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /marketing/paygiftactivity/activities")]
public async Task TestExecuteQueryMarketingPayGiftActivities()
{
var request = new Models.QueryMarketingPayGiftActivitiesRequest();
var response = await TestClients.Instance.ExecuteQueryMarketingPayGiftActivitiesAsync(request);

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteMerchantMediaTests
public class TestCase_ApiExecuteExecuteMerchantMediaTests
{
[Fact(DisplayName = "[POST] /merchant/media/upload")]
public async Task UploadMerchantServiceImageTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /merchant/media/upload")]
public async Task TestExecuteUploadMerchantServiceImage()
{
var request = new Models.UploadMerchantMediaImageRequest()
{
@ -23,8 +23,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.MediaId);
}
[Fact(DisplayName = "[POST] /merchant/media/video_upload")]
public async Task UploadMerchantServiceVideoTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /merchant/media/video_upload")]
public async Task TestExecuteUploadMerchantServiceVideo()
{
var request = new Models.UploadMerchantMediaVideoRequest()
{

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteMerchantServiceTests
public class TestCase_ApiExecuteExecuteMerchantServiceTests
{
[Fact(DisplayName = "[GET] /merchant-service/complaints-v2")]
public async Task QueryMerchantServiceComplaintsTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /merchant-service/complaints-v2")]
public async Task TestExecuteQueryMerchantServiceComplaints()
{
var request = new Models.QueryMerchantServiceComplaintsRequest()
{
@ -31,8 +31,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
}
}
[Fact(DisplayName = "[GET] /merchant-service/complaints-v2/{merchant_id}")]
public async Task GetMerchantServiceComplaintByComplaintIdTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /merchant-service/complaints-v2/{merchant_id}")]
public async Task TestExecuteGetMerchantServiceComplaintByComplaintId()
{
var request = new Models.GetMerchantServiceComplaintByComplaintIdRequest()
{
@ -47,8 +47,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.True(response.UserComplaintTimes >= 1);
}
[Fact(DisplayName = "[GET] /merchant-service/complaints-v2/{merchant_id}/negotiation-historys")]
public async Task QueryMerchantServiceComplaintNegotiationHistoriesTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /merchant-service/complaints-v2/{merchant_id}/negotiation-historys")]
public async Task TestExecuteQueryMerchantServiceComplaintNegotiationHistories()
{
var request = new Models.QueryMerchantServiceComplaintNegotiationHistoriesRequest()
{
@ -68,8 +68,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
}
}
[Fact(DisplayName = "[POST] /merchant-service/complaint-notifications")]
public async Task CreateMerchantServiceComplaintNotificationTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /merchant-service/complaint-notifications")]
public async Task TestExecuteCreateMerchantServiceComplaintNotification()
{
var request = new Models.CreateMerchantServiceComplaintNotificationRequest()
{
@ -82,8 +82,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.NotifyUrl);
}
[Fact(DisplayName = "[GET] /merchant-service/complaint-notifications")]
public async Task GetMerchantServiceComplaintNotificationTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /merchant-service/complaint-notifications")]
public async Task TestExecuteGetMerchantServiceComplaintNotification()
{
var request = new Models.GetMerchantServiceComplaintNotificationRequest();
var response = await TestClients.Instance.ExecuteGetMerchantServiceComplaintNotificationAsync(request);
@ -93,8 +93,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.NotifyUrl);
}
[Fact(DisplayName = "[PUT] /merchant-service/complaint-notifications")]
public async Task UpdateMerchantServiceComplaintNotificationTest()
[Fact(DisplayName = "测试用例:调用 API [PUT] /merchant-service/complaint-notifications")]
public async Task TestExecuteUpdateMerchantServiceComplaintNotification()
{
var request = new Models.UpdateMerchantServiceComplaintNotificationRequest()
{
@ -107,8 +107,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.NotifyUrl);
}
[Fact(DisplayName = "[DELETE] /merchant-service/complaint-notifications")]
public async Task DeleteMerchantServiceComplaintNotificationTest()
[Fact(DisplayName = "测试用例:调用 API [DELETE] /merchant-service/complaint-notifications")]
public async Task TestExecuteDeleteMerchantServiceComplaintNotification()
{
var request = new Models.DeleteMerchantServiceComplaintNotificationRequest();
var response = await TestClients.Instance.ExecuteDeleteMerchantServiceComplaintNotificationAsync(request);
@ -116,8 +116,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.True(response.IsSuccessful());
}
[Fact(DisplayName = "[POST] /merchant-service/images/upload")]
public async Task UploadMerchantServiceImageTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /merchant-service/images/upload")]
public async Task TestExecuteUploadMerchantServiceImage()
{
var request = new Models.UploadMerchantServiceImageRequest()
{

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecutePayTransactionsTests
public class TestCase_ApiExecuteExecutePayTransactionsTests
{
[Fact(DisplayName = "[POST] /pay/transactions/app")]
public async Task CreatePayTransactionAppTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /pay/transactions/app")]
public async Task TestExecuteCreatePayTransactionApp()
{
var request = new Models.CreatePayTransactionAppRequest()
{
@ -28,8 +28,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.PrepayId);
}
[Fact(DisplayName = "[POST] /pay/transactions/jsapi")]
public async Task CreatePayTransactionJsapiTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /pay/transactions/jsapi")]
public async Task TestExecuteCreatePayTransactionJsapi()
{
var request = new Models.CreatePayTransactionJsapiRequest()
{
@ -52,8 +52,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.PrepayId);
}
[Fact(DisplayName = "[POST] /pay/transactions/h5")]
public async Task CreatePayTransactionH5Test()
[Fact(DisplayName = "测试用例:调用 API [POST] /pay/transactions/h5")]
public async Task TestExecuteCreatePayTransactionH5()
{
var request = new Models.CreatePayTransactionH5Request()
{
@ -71,8 +71,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.H5Url);
}
[Fact(DisplayName = "[POST] /pay/transactions/native")]
public async Task CreatePayTransactionNativeTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /pay/transactions/native")]
public async Task TestExecuteCreatePayTransactionNative()
{
var request = new Models.CreatePayTransactionNativeRequest()
{
@ -90,8 +90,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.QrcodeUrl);
}
[Fact(DisplayName = "[GET] /pay/transactions/id/{transaction_id}")]
public async Task GetPayTransactionByIdTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /pay/transactions/id/{transaction_id}")]
public async Task TestExecuteGetPayTransactionById()
{
var request = new Models.GetPayTransactionByIdRequest()
{
@ -108,8 +108,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.True(response.Amount.Total > 0);
}
[Fact(DisplayName = "[GET] /pay/transactions/out-trade-no/{out_trade_no}")]
public async Task GetPayTransactionByOutTradeNumberTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /pay/transactions/out-trade-no/{out_trade_no}")]
public async Task TestExecuteGetPayTransactionByOutTradeNumber()
{
var request = new Models.GetPayTransactionByOutTradeNumberRequest()
{
@ -125,8 +125,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.True(response.Amount.Total > 0);
}
[Fact(DisplayName = "[POST] /pay/transactions/out-trade-no/{out_trade_no}/close")]
public async Task ClosePayTransactionTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /pay/transactions/out-trade-no/{out_trade_no}/close")]
public async Task TestExecuteClosePayTransaction()
{
var request = new Models.ClosePayTransactionRequest()
{

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteProfitSharingTests
public class TestCase_ApiExecuteExecuteProfitSharingTests
{
[Fact(DisplayName = "[POST] /profitsharing/receivers/add")]
public async Task AddProfitSharingReceiverTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /profitsharing/receivers/add")]
public async Task TestExecuteAddProfitSharingReceiver()
{
await TestClients.InitializeCertificateManagerAsync();

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayExecuteRefundTests
public class TestCase_ApiExecuteExecuteRefundTests
{
[Fact(DisplayName = "[POST] /refund/domestic/refunds")]
public async Task CreateRefundDomesticRefundTest()
[Fact(DisplayName = "测试用例:调用 API [POST] /refund/domestic/refunds")]
public async Task TestExecuteCreateRefundDomesticRefund()
{
var request = new Models.CreateRefundDomesticRefundRequest()
{
@ -36,8 +36,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.True(response.Amount.PayerRefund > 0);
}
[Fact(DisplayName = "[GET] /refund/domestic/refunds/{out_refund_no}")]
public async Task GetRefundDomesticRefundByOutRefundNumberTest()
[Fact(DisplayName = "测试用例:调用 API [GET] /refund/domestic/refunds/{out_refund_no}")]
public async Task TestExecuteGetRefundDomesticRefundByOutRefundNumber()
{
var request = new Models.GetRefundDomesticRefundByOutRefundNumberRequest()
{

View File

@ -3,10 +3,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayCertificateManagerTests
public class TestCase_CertificateManagerTests
{
[Fact(DisplayName = "序列化与反序列化 `CertificateEntry`")]
public void CertificateEntrySerializationTest()
[Fact(DisplayName = "测试用例:`CertificateEntry` 序列化")]
public void TestCertificateEntrySerialization()
{
var entry = new Settings.CertificateEntry("SN", "-----BEGIN CERTIFICATE-----END CERTIFICATE-----", DateTimeOffset.Now, DateTimeOffset.Now);

View File

@ -9,14 +9,14 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayDeclarationTests
public class TestCase_CodeReviewAnalyzer
{
private static readonly Assembly _assembly = Assembly.Load("SKIT.FlurlHttpClient.Wechat.TenpayV3");
private Assembly SourceAssembly { get; } = Assembly.Load("SKIT.FlurlHttpClient.Wechat.TenpayV3");
[Fact(DisplayName = "验证 API 模型命名")]
[Fact(DisplayName = "代码评审:分析 API 模型命名")]
public void ApiModelsNamingTest()
{
CodeStyleUtil.VerifyApiModelsNaming(_assembly, out var ex);
CodeStyleUtil.VerifyApiModelsNaming(SourceAssembly, out var ex);
if (ex != null)
throw ex;
@ -24,11 +24,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Null(ex);
}
[Fact(DisplayName = "验证 API 模型定义")]
[Fact(DisplayName = "代码评审:分析 API 模型定义")]
public void ApiModelsDefinitionTest()
{
string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "ModelSamples");
CodeStyleUtil.VerifyApiModelsDefinition(_assembly, workdir, out var ex);
CodeStyleUtil.VerifyApiModelsDefinition(SourceAssembly, workdir, out var ex);
if (ex != null)
throw ex;
@ -36,11 +36,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Null(ex);
}
[Fact(DisplayName = "验证 API 事件定义")]
[Fact(DisplayName = "代码评审:分析 API 事件定义")]
public void ApiEventsDefinitionTest()
{
string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "EventSamples");
CodeStyleUtil.VerifyApiEventsDefinition(_assembly, workdir, out var ex);
CodeStyleUtil.VerifyApiEventsDefinition(SourceAssembly, workdir, out var ex);
if (ex != null)
throw ex;
@ -48,10 +48,10 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Null(ex);
}
[Fact(DisplayName = "验证 API 接口命名")]
[Fact(DisplayName = "代码评审:分析 API 接口命名")]
public void ApiExtensionsNamingTest()
{
CodeStyleUtil.VerifyApiExtensionsNaming(_assembly, out var ex);
CodeStyleUtil.VerifyApiExtensionsNaming(SourceAssembly, out var ex);
if (ex != null)
throw ex;
@ -59,7 +59,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Null(ex);
}
[Fact(DisplayName = "验证代码规范")]
[Fact(DisplayName = "代码评审:分析代码规范")]
public void CodeStyleTest()
{
string workdir = Path.Combine(TestConfigs.ProjectSourceDirectory);

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class TestCase_HashUtilityTests
{
[Fact(DisplayName = "测试用例SHA-256 信息摘要")]
public void TestSHA256Hash()
{
string rawData = "SHA256HashTest";
string actualHash = Utilities.SHA256Utility.Hash(rawData);
string expectedHash = "8446f1ce5ca8b4a87c0d0cc15be4ba173b2ff78dc33c5f6731d877dcd2d8f401";
Assert.Equal(expectedHash, actualHash, ignoreCase: true);
}
}
}

View File

@ -7,7 +7,7 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayRequestEncryptionTests
public class TestCase_RequestEncryptionTests
{
private const string RSA_CERTSN = "mock_sn";
private const string RSA_CERTIFICATE = "-----BEGIN CERTIFICATE-----MIID9jCCAt6gAwIBAgIUFGJAVFxIU/1hoxpZC8Tc2xKFJHowDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsTFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3QgQ0EwHhcNMjAwODAxMDczNTE5WhcNMjUwNzMxMDczNTE5WjCBhzETMBEGA1UEAwwKMTYwMTEwMzMxNDEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQLDCroo5XkurrvvIjkuIrmtbfvvInmlZnogrLnp5HmioDmnInpmZDlhazlj7gxCzAJBgNVBAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKq4IUw5Rq6iTUahjkr+aYvmn3Hg2tHNDyIru7ZdthXw27BCwnwwDyufq6SBwXypuf3wXKpcFggZo5dwjDR6XxlGXzNDKdW7JQkTxQXqABZZVCq4yMMkVns3xbmDfAI57bW0O0F40+NOqmU9gjqRwGNvE9bE8N3y2VyxYcz53rU4FCrlCOfsFeF1Z3usbWOK5IOYXjmdzr96xVWasO0URJ60GwDZyGxRdkzd5kJy6HnVVqOUbn3t7mKbGkzQq/j+D+pyMlhjtRV475ks5uex4gVWZgEqT1b9sx1pUQvVPr6/ZXtqTJwSg/YvSCx5RBiYCskAyA/5XH9t1p/WV1zFhXUCAwEAAaOBgTB/MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTwMGUGA1UdHwReMFwwWqBYoFaGVGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMvaXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4RUJEMjANBgkqhkiG9w0BAQsFAAOCAQEAU44msdPGFg/r5JcWgUDEXWOqqCDiFNjWbhM/rO0A3TCV0yP5o7Se/yLsDizHGTUzZ2qg3bC02nn4RysEyMVQ+9tXsOtXQBHrmoZ5vS8ndqbE1YO33N6zxIUb0IN3yGZh3oVmQgTYYe1is4i5Sfiy7JdR6/uUrwQN13fzPaDCnNx6iVzrPSJJf1xiFdtpFFtK021prjMYG7csHiFQeelgyE8XtlQuLk0tsHBrJ2FHSdV4HISqONz0hMPL0xsZkBD/L/bvR3L0lqe8bsHOBCJOMyjxucI21mBRd7tc4AGiJlQt5jrUrbos5hul4/QUq7hFfZNDrEBMINbMyIpYWRbIqQ==-----END CERTIFICATE-----";
@ -28,8 +28,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
});
}, isThreadSafe: false);
[Fact(DisplayName = "加密请求中的敏感数据([POST] /profitsharing/receivers/add")]
public void DecryptResponseSensitiveProperty_AddProfitSharingReceiverRequest()
[Fact(DisplayName = "测试用例:加密请求中的敏感数据([POST] /profitsharing/receivers/add")]
public void TestEncryptResponseSensitiveProperty_AddProfitSharingReceiverRequest()
{
var mock = new Models.AddProfitSharingReceiverRequest()
{
@ -40,11 +40,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(RSA_CERTSN, data.WechatpayCertSerialNumber);
Assert.Equal(MockText, data.Account);
Assert.Equal(MockText, Utilities.RSAUtility.DecryptWithECB(RSA_PRIVATE_KEY, data.Name));
Assert.Equal(MockText, Utilities.RSAUtility.DecryptWithECB(RSA_PRIVATE_KEY, data.Name!));
}
[Fact(DisplayName = "加密请求中的敏感数据([POST] /profitsharing/orders")]
public void DecryptResponseSensitiveProperty_CreateProfitSharingOrderRequest()
[Fact(DisplayName = "测试用例:加密请求中的敏感数据([POST] /profitsharing/orders")]
public void TestEncryptResponseSensitiveProperty_CreateProfitSharingOrderRequest()
{
var mock = new Models.CreateProfitSharingOrderRequest()
{
@ -61,7 +61,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(RSA_CERTSN, data.WechatpayCertSerialNumber);
Assert.Equal(MockText, data.ReceiverList[0].Account);
Assert.Equal(MockText, Utilities.RSAUtility.DecryptWithECB(RSA_PRIVATE_KEY, data.ReceiverList[0].Name));
Assert.Equal(MockText, Utilities.RSAUtility.DecryptWithECB(RSA_PRIVATE_KEY, data.ReceiverList[0].Name!));
}
}
}

View File

@ -8,7 +8,7 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayResponseDecryptionTests
public class TestCase_ResponseDecryptionTests
{
private const string RSA_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCd094X2jr6wrL1pIBTSbKX5hVqxyCJhKLqaf31KQsw2LdzfXEOL45KiYr6IshwZaSPFok7Sq+1wLrO6/DZ7/GSmzVwdFIV/zjDbI3jaSHt69ZAJGBS212AzC4cwHvpGrHm3kqzVifJyUNxsoTvWklRGSE50pPWaXoxmdPgD5da8IPDHNzkPM0QYTOlHmIRsDQZpWiZRPaFdrN3i/qG9toCRCPVptCVNYrWLDEFXh3ioOqOdTk1fHxFczaNf4YvQhsqXlG/lGiqGbuPuFYfF/RvS9KfptAM1yycknTslkSeiOpA22sFbDdb+m7DHv+nc8DQPPmD7SxDwVIDTcIS7pEJAgMBAAECggEAM6E+czEZwDR3FLKGpDhkqxpCgVa4xyPTo7mesVeG6KjMgoRTup9F/g42n5NHXLVzereVlwbcqiltMwmuFa1PqnUJq0ryG24NZKibVfxrdAiFYyBDPneyg9LHdvJk1qG79tlbOIWDqJglbwlGQYKYn2YIH4FKiYahyZ4X2KFhEwc9mWydHSOyN8zOOJcRCy1FzUcUvITRKob+Q9epz9/4/VX0g1AnB6FwIR5pBqwMYLSv+g+JxfVKPRnSaIxq/2HOvhiyJ7fUqX1yGI+konJJHrn66JIux8xt4SxEnomZBveHlOMUTgTqovxpXisbvXQGBDV7dwW/qhGZet6h57qogQKBgQDNFLP9S6aPnwseeavxK0ygQpgJRbXbHCyqH/mVA/Pg9DaIhxl7+JCC1lS/JuZslow4t3JvjwixAzQEz9SkwUuiRO5vUWb5R+DZJ8HeqtMfoll6wxepu1TQT1pTPnSHliJQP15k5AQ1bkTZjcGA79iUmkksa4EP/GWtOooE8JhMEQKBgQDFA6oyBtbMyWlnGmdsieQuRsjCklZhPL93INX5VUfcfRqQdhqrmoaJg+OZTwVrARp6VHGEaURBTSj6bSoRbBckFNxjVsL6Utpgof+ZWmr5u8ZGHGHIPJMLt7GxI9SItpNNNY33OiUkkfSH4zHK5KZeG9sKKraQwITJCwLZUnnNeQKBgChHkLKHUUeULVLnAuZzYrF3YvUvQ/CtL/iaHyMti5D7Zlqabl7zCy8nea2xrkBVsWTSYx+WMFbUEjt/tnxFmt1cPJiQnHEJtRfxvxpE4wKrmHeMKfGkYZwoec0vzyNyUXsBd0DJqCn2Zn90YDU65ocJZqXa15aUNEQ54zHlL4SBAoGAHbve3OwBUSj4unHWuB/bi0xtkkgJt2U2tGEFSjsfvFw5PSJGBi4tLeX03Ld7ZtnkyB+kfkpw3bYqgBknpzd8CpsHZAq9JJCKmtj4PYnS6Vv4oa4458KUoskXjVeOBRAhDR8PDQf+gRVyJWwZoLh/j2Z+2Xr20MPthnYd+PSko2kCgYBra4rMhYx2Hg0rRe2O7ju+MPm+JK01VpbvwDTnEPnYgMImDmLAXF6GljCt3iy/8X1WcjMPxGjTJ/xfTMne/aqKwvPhZCBL4DdNLNRzppCovsaaMHzrQzy4cvg0IEhIprFeR7ED4eMs8zLUhl3vgNhHOkeQ7cyuEnTl5wB9xOkbSw==-----END PRIVATE KEY-----";
private const string RSA_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAndPeF9o6+sKy9aSAU0myl+YVascgiYSi6mn99SkLMNi3c31xDi+OSomK+iLIcGWkjxaJO0qvtcC6zuvw2e/xkps1cHRSFf84w2yN42kh7evWQCRgUttdgMwuHMB76Rqx5t5Ks1YnyclDcbKE71pJURkhOdKT1ml6MZnT4A+XWvCDwxzc5DzNEGEzpR5iEbA0GaVomUT2hXazd4v6hvbaAkQj1abQlTWK1iwxBV4d4qDqjnU5NXx8RXM2jX+GL0IbKl5Rv5Roqhm7j7hWHxf0b0vSn6bQDNcsnJJ07JZEnojqQNtrBWw3W/puwx7/p3PA0Dz5g+0sQ8FSA03CEu6RCQIDAQAB-----END PUBLIC KEY-----";
@ -21,8 +21,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
});
}, isThreadSafe: false);
[Fact(DisplayName = "解密响应中的敏感数据([GET] /certificates")]
public async Task DecryptResponseSensitiveProperty_QueryCertificatesResponse()
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /certificates")]
public async Task TestDecryptResponseSensitiveProperty_QueryCertificatesResponse()
{
var client1 = new WechatTenpayClient(new WechatTenpayClientOptions()
{
@ -51,8 +51,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.DoesNotContain(response2.CertificateList, (e => e.EncryptCertificate.CipherText.StartsWith("-----BEGIN CERTIFICATE-----")));
}
[Fact(DisplayName = "解密响应中的敏感数据([GET] /ecommerce/applyments/out-request-no/{out_request_no}")]
public void DecryptResponseSensitiveProperty_GetEcommerceApplymentByOutRequestNumberResponseTest()
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /ecommerce/applyments/out-request-no/{out_request_no}")]
public void TestDecryptResponseSensitiveProperty_GetEcommerceApplymentByOutRequestNumberResponseTest()
{
var mock = new Models.GetEcommerceApplymentByOutRequestNumberResponse()
{
@ -70,14 +70,14 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
var data = MockClientInstance.Value.DecryptResponseSensitiveProperty(mock);
Assert.Equal(MockText, data.ApplymentState);
Assert.Equal(MockText, data.AccountValidation.AccountNumber);
Assert.Equal(MockText, data.AccountValidation.DestinationAccountName);
Assert.Equal(MockText, data.AccountValidation.DestinationAccountNumber);
Assert.Equal(MockText, data.AccountValidation.AccountName);
Assert.Equal(MockText, data.AccountValidation!.AccountNumber);
Assert.Equal(MockText, data.AccountValidation!.DestinationAccountName);
Assert.Equal(MockText, data.AccountValidation!.DestinationAccountNumber);
Assert.Equal(MockText, data.AccountValidation!.AccountName);
}
[Fact(DisplayName = "解密响应中的敏感数据([GET] /ecommerce/bill/fundflowbill")]
public void DecryptResponseSensitiveProperty_GetEcommerceBillFundflowBillResponse()
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /ecommerce/bill/fundflowbill")]
public void TestDecryptResponseSensitiveProperty_GetEcommerceBillFundflowBillResponse()
{
var mock = new Models.GetEcommerceBillFundflowBillResponse()
{
@ -106,8 +106,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(MockText, data.DownloadBillList[1].EncryptKey);
}
[Fact(DisplayName = "解密响应中的敏感数据([GET] /merchant-service/complaints-v2/{complaint_id}")]
public void DecryptResponseSensitiveProperty_GetMerchantServiceComplaintByComplaintIdResponse()
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /merchant-service/complaints-v2/{complaint_id}")]
public void TestDecryptResponseSensitiveProperty_GetMerchantServiceComplaintByComplaintIdResponse()
{
var mock = new Models.GetMerchantServiceComplaintByComplaintIdResponse()
{
@ -129,8 +129,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(MockText, data.ComplaintOrderList[0].TransactionId);
}
[Fact(DisplayName = "解密响应中的敏感数据([GET] /merchant-service/complaints-v2")]
public void DecryptResponseSensitiveProperty_QueryMerchantServiceComplaintsResponse()
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /merchant-service/complaints-v2")]
public void TestDecryptResponseSensitiveProperty_QueryMerchantServiceComplaintsResponse()
{
var mock = new Models.QueryMerchantServiceComplaintsResponse()
{
@ -150,8 +150,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(MockText, data.ComplaintList[0].PayerOpenId);
}
[Fact(DisplayName = "解密响应中的敏感数据([GET] /smartguide/guides")]
public void DecryptResponseSensitiveProperty_QuerySmartGuidesResponse()
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /smartguide/guides")]
public void TestDecryptResponseSensitiveProperty_QuerySmartGuidesResponse()
{
var mock = new Models.QuerySmartGuidesResponse()
{
@ -173,8 +173,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(MockText, data.GuideList[0].UserMobile);
}
[Fact(DisplayName = "解密响应中的敏感数据([GET] /transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no}")]
public void DecryptResponseSensitiveProperty_GetTransferBatchDetailByOutDetailNumberResponse()
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no}")]
public void TestDecryptResponseSensitiveProperty_GetTransferBatchDetailByOutDetailNumberResponse()
{
var mock = new Models.GetTransferBatchDetailByOutDetailNumberResponse()
{
@ -188,7 +188,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(MockText, data.OpenId);
}
[Fact(DisplayName = "解密响应中的敏感数据([GET] /transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id}")]
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id}")]
public void DecryptResponseSensitiveProperty_GetTransferBatchDetailByDetailIdResponse()
{
var mock = new Models.GetTransferBatchDetailByDetailIdResponse()
@ -203,8 +203,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(MockText, data.OpenId);
}
[Fact(DisplayName = "解密响应中的敏感数据([GET] /partner-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id}")]
public void DecryptResponseSensitiveProperty_GetPartnerTransferBatchDetailByDetailIdResponse()
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /partner-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id}")]
public void TestDecryptResponseSensitiveProperty_GetPartnerTransferBatchDetailByDetailIdResponse()
{
var mock = new Models.GetPartnerTransferBatchDetailByDetailIdResponse()
{

View File

@ -7,10 +7,10 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpayResponseVerificationTests
public class TestCase_ResponseVerificationTests
{
[Fact(DisplayName = "验证响应签名")]
public async Task VerifyResponseSignatureTest()
[Fact(DisplayName = "测试用例:验证响应签名")]
public async Task TestVerifyResponseSignature()
{
await TestClients.InitializeCertificateManagerAsync();

View File

@ -7,7 +7,7 @@ using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
public class WechatTenpaySecurityTests
public class TestCase_RsaUtilityTests
{
// 此处测试的 RSA 证书/公钥/私钥是自签名生成的,仅供执行 RSA 相关的单元测试,不能用于调用微信支付 API。
private const string RSA_CERT_SN = "3050f72e2dce03e7efe49557dd231d176649afbd";
@ -17,22 +17,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
private const string RSA_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA52DszUZzPKPo1d9Hi5Hj\nlu7OINwADaeXifA4rvmJJaA+jm4DCMwrAMzyS12EiW31xCAF8LZ/xkrFHO5CZgvK\n87Y+kY9DmhvNX6FVYsn4ay7KER0zo87zqQjC+njUu1rYuKnio7MYb354PitwQ3SW\nNv2qTCbCNCXTN9pJXNhlCudWCEWrNrYc4/hKz3bqu1DjpY0oHuuKPk/iRr2TTUIA\nwahNkNQheQNB2a8hL7L2OG1Sn1vaDWe+5RJYlMRZ3NgYDTqoy8GMs+6q091MQMDl\nQ90jtW/JEoM5DUyI8zfQfDLGnU7FuY0rrZ/+6OQT/o7ISf0OR5TISS0lqnDN3vVa\nph0ftDGRdGqJk2SJAHIoxp5gt410rfWS9kpSDFJs3Pvt4rtNZBYvkGD8obSm91br\nAkoX4+u1Y4p1qZpWJ4LIKw8oyeieqlLZtF/VGKOtKxe/IKn8GwoQJLx4dUGFOqM7\nHPwR9cyjMaC1o3V1NQG+1wD9TLtGh3WXUFJRYDmePaSp39GFPupTMlPRbD0RK80B\n6xv2rYTyYyd8s2LN6P6Hh/nFIkc1rekIf9JhPy0WKzrXdmnfjSHKPxmz0WSYN8Fx\nKasqcJhncOdhLTzzVEhj9xHSI8ejP2fJ4v+ARoD3GURPD9H7KMa7xmzRSAZ8A8LM\n3uvdJNhbKBwWqvo45ncz+7cCAwEAAQ==\n-----END PUBLIC KEY-----";
private const string RSA_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n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\nhpUq0eKgdGHc2R4r57soRvGoGy2DtA==\n-----END PRIVATE KEY-----";
[Fact(DisplayName = "证书和回调报文解密AES-GCM")]
public void AESGCMDecryptTest()
{
string key = "f09b03a7a1902b5b4913856f1fd07ab1";
string iv = "aae8c2e79c5b";
string aad = "certificate";
string cipherText = "x9kkL5w1JuaypcjhrYIP+kVNlN8o8uN4yJyJjy5lg+PyPnQL2Zn//ORaXAyzdaK/WBMVd3u/Y9hLaTBLMyRXzowsrkJ5PT37johye48N7BAJQ0PJwW++d1RdhOOPjoqfmws6rSV5Gv2qhfdKjmpxVjr8xr71dtBt8J2wu+bAV99HHQoAynm/Pp9OQYZgpOQ+1cyFHd43TAxOoFfmixKrXr3HP8lJot0XCUSq4qkr1Hs44FV2KuzntSk8eqKr5N17UcuPF3VYnnnF/AvQ7HuLKWwrHhUbaXfkwy0Q2n36UJMfBj7344S97E8BnS89ojgOPQi+olBPyNgrtDWHgsJAKu7HA6PV/FgmXcrZirje/AH1u25es4z5xItHscm//6rDvALgf7greV5OJzMsSl/KVDtbkjDSzim0j4ZTduIfzh7l6jfOz115ITcNILT9ef2KkcMyBBc89GZlMGeHTbgsBHzGeLawX3dXFjqt5aMnHM3VWCovA2aUM4c//rqkZGf+Va86OEFoJQLiSTFpkOrKxcIxcrbKPLTgiDWRT3wzmnUDg7kSPbluzt3ROvMFq9lB8bO/pBd7TD2w87sfUdKLj69FniX6s37SBeRVhw8GSIvBf5lpLUhqL5zKYlbuAWePuz0wVV4NTtkaVKZlmm8KTODyZDFpsyKPubDDcwT1ftRf5aSVM4x04I/1B7GkNz/TOy+zpJ0h0B7VHdxyO5JYiI/1qsatX/FE2aJdQYMYOtqfDH7ZH5UUKIqo538OKvE2M4MlBR/aVE4z4QDKfE/1kYrOfvVGfDzF/FWHfUrcqB8kdQMvk8vCoM8yYZsX4KE1aoJbNM2pWv2tpr9JE8b/VQgUyHOgPYAha+UOmZki4Sfl9H62687EIWdbM57ZxmwIiBp60SrJLiBfZon9JqXKdtJOKj0CRokQiBnONNXCVerLFeBNQfeKRw8tgJXf+QPohMGYkSDdc8hTgdbmhTwB1Vv01stlYK12QMNRCovlp/fcmpB72Phlq+/3p5pqMzknw+qm5QAz7JnpZJCFHit52gHwAkKRkVPB3HF2rfLrdTYz5c9Bok1ICAY9My47eLFdduIe99V52cjMLQuUmNFBPrDdyZKVqIHJ/wtWO/wIFpAVGSJMHctyEKmeJVc1IQN74Wm00PrpPackHdO3G41bBmkp5pqUdsSgSkwdfNVqv0cMcSe04NrRGNKMcZ7TA/CMaP1YnhxvVE+z8aksJqSJ+gdplvuwl40y5C8UEHeAi1V8Q0Bf4YvYRgOVIWm2Lzjdn2z9PWLGcStUj11/1hthk2li4V3mgm2Cr2IZme2sn4rZmJ6dexGP1nk+ZYOq0xLE8F7oex9gyDN+A/6zHqnuhO/X08qye0gochMr8U89Qvj2c0L3P2mjCea2H1mEriAJPqMPMKIinh1lQJEZufnfCcPxbZLKTtl6zHtHgOztejd1gV/nUyCVKD4MCMfBDy9C/Af8pWx6akOg/QSQNIGA2AI6zprHn9zEjpFIzXJYvruVI22Yt6oF9Xnt7Ki82wRK2M96r4kj6cwSs4exMPGv8fWMrFTm0Br6p6T+HZsxyyn2ChuPIgpfisnce/ZaU/0xCZhK/K79+TK2GeeChq5oEpua/1tx4+kDHi7H9381pLJmy2oXW060c2mmwA9+EpcuwEDhr8fsnghbv41u7b1NhEmWNVUy29Dwaz61PPGUdh5DsvaKLWC+raZ/6UEKPw+tiABJ5o6u2jAWgmEYmmJCKapNgtfPc6D+O0aHH9oqh6u4+8NRAhusPZzDGWBr6AT4pexgWFeEhZhn6bXM9HhpUe0IhOTw5D+tqXrTlNon4kjYibiMUFy1h2YyYS3IEdu1J4xqvo0rFyCxF1C+P6ubc0tClRPkXg==";
string actualPlain = Utilities.AESUtility.DecryptWithGCM(key: key, iv: iv, aad: aad, cipherText: cipherText);
string expectedPlain = "-----BEGIN CERTIFICATE-----\nMIID3DCCAsSgAwIBAgIUGZNrTcamx3sFSJsQli3v9C6gZe8wDQYJKoZIhvcNAQEL\nBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\nFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\nQ0EwHhcNMjAwODAxMDczNTE4WhcNMjUwNzMxMDczNTE4WjBuMRgwFgYDVQQDDA9U\nZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl\nbnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo\nZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOAYHqxCqaRzoTIvgV\nixaYJJvmvHbiczbx5MQ9XL1ITSFxkTsNsk7RKHnO7eBS5imheJgQwd22Ky+XclSe\n7B4odssu/l/+gHo2gooTYrrCpQrOkpvGMf8R8aI56BQIF+vsomDvVq1NojHV2Fql\njMwFXzhj2EmU6p6gDv9iL7q1NrfnxFx8iJe4OhIB5Ek4qn1xXxrTUhiULd2vXlbI\nXhRetZSNcJsLt5Rw7D7c8F+aX2JchfeqsZECwKW7bSjMbVWWC6M9MgkB/aId8P0y\n7qEiiXFJkfkg1I/E1ud2apopsid5tdCyRRR6+MhhX2EC8S04MN4soUT7haqNNxX2\nrKHnAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBc\nMFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3Js\nP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJ\nKoZIhvcNAQELBQADggEBAJyg2z4oLQmPfftLQWyzbUc9ONhRMtfA+tVlVBgtLLKn\nWuDlsmEntheM07fu84F4pcfs3yHzjD7pAOFbO4Yt1yhQ50DK35sjbRWepPdWJZLl\nni7KBctcmm0o4zq37oB7vonmBEbFqYs9DaINYOjgI3J25iSBkPVC7dBbvFj2xB0L\ncIcXipq30tDdC/oUem27MNzwZAt49WthKhw6u3HSkcE5cO4LyYTsJhSyG/7LXwvV\nMgX4Jyzo0SSiGOU1/beaZssTVI8sTPJVlHWjhNE3Lc2SaAlKGfGwvt0X3cEZEF+7\noEZIFTkkAF2JhqfnpR3gST0G8Umq1SaVtCPP/zVI8x0=\n-----END CERTIFICATE-----";
Assert.Equal(expectedPlain, actualPlain);
}
[Fact(DisplayName = "从 RSA 证书中导出公钥")]
public void ExportRSAPublicKeyFromCertificateTest()
[Fact(DisplayName = "测试用例:从 RSA 证书中导出公钥")]
public void TestExportRSAPublicKeyFromCertificate()
{
string actualPublicKey = Utilities.RSAUtility.ExportPublicKey(RSA_CERTIFICATE).Replace("\r", "").Replace("\n", "");
string expectedPublicKey = RSA_PUBLIC_KEY.Replace("\r", "").Replace("\n", "");
@ -40,8 +26,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(expectedPublicKey, actualPublicKey, ignoreLineEndingDifferences: true);
}
[Fact(DisplayName = "从 RSA 证书中导出证书序列号")]
public void ExportRSASerialNumberFromCertificateTest()
[Fact(DisplayName = "测试用例:从 RSA 证书中导出证书序列号")]
public void TestExportRSASerialNumberFromCertificate()
{
string actualSerialNumber = Utilities.RSAUtility.ExportSerialNumber(RSA_CERTIFICATE);
string expectedSerialNumber = RSA_CERT_SN;
@ -49,8 +35,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(expectedSerialNumber, actualSerialNumber);
}
[Fact(DisplayName = "从 RSA 证书中导出证书颁发时间")]
public void ExportRSAEffectiveTimeFromCertificateTest()
[Fact(DisplayName = "测试用例:从 RSA 证书中导出证书颁发时间")]
public void TestExportRSAEffectiveTimeFromCertificate()
{
DateTimeOffset actualEffectiveTime = Utilities.RSAUtility.ExportEffectiveTime(RSA_CERTIFICATE);
DateTimeOffset expectedEffectiveTime = DateTimeOffset.Parse(RSA_CERT_START_DATE);
@ -58,8 +44,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(expectedEffectiveTime, actualEffectiveTime);
}
[Fact(DisplayName = "从 RSA 证书中导出证书过期时间")]
public void ExportRSAExpireTimeFromCertificateTest()
[Fact(DisplayName = "测试用例:从 RSA 证书中导出证书过期时间")]
public void TestExportRSAExpireTimeFromCertificate()
{
DateTimeOffset actualExpireTime = Utilities.RSAUtility.ExportExpireTime(RSA_CERTIFICATE);
DateTimeOffset expectedExpireTime = DateTimeOffset.Parse(RSA_CERT_END_DATE);
@ -67,8 +53,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(expectedExpireTime, actualExpireTime);
}
[Fact(DisplayName = "签名生成SHA256WithRSA")]
public void SHA256WithRSASignTest()
[Fact(DisplayName = "测试用例SHA256WithRSA 签名生成")]
public void TestRSASignatureSHA256WithRSASign()
{
string plainText = "SHA256WithRSASignTest";
string actualSign = Utilities.RSAUtility.SignWithSHA256(RSA_PRIVATE_KEY, plainText);
@ -77,8 +63,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(expectedSign, actualSign);
}
[Fact(DisplayName = "签名验证SHA256WithRSA")]
public void SHA256WithRSAVerifyTest()
[Fact(DisplayName = "测试用例SHA256WithRSA 签名验证")]
public void TestRSASignatureSHA256WithRSAVerify()
{
string plainText = "SHA256WithRSAVerifyTest";
string signText = "aHX+MrmZHDEraMKBEPV2Vnps1B9b25lGbv/rdppx/S7+oaXtjKJprzCq5H7RCpvrKS3xYIeTEPwQGC3Vots7dCdLi8v8ew1vvtXf8qNAnd7CTMHqu3wSohXzgyASTmNbXE2ml9LbWYPPYMvPJXROQbGVjoOrsErWBPPJYXuO3lIckIfwI05OTdl4H3+BvpD/ZoljRp8Qgo9+paGvarBc++TaAh0FXnQf0TGNFUIeHHiAKBee5oCBTuZZM9J5RPw0oIq/g7Wun+e/zWiwVBPHltOgZrV46uagSAE6nBDHk+hlNxDivCxkJdBVCSIYFFmBXIcnGZ/u4ZfBui/k1jGoKibyvPK4z2+6GSlj41Yo81kuSBfzLiSsx33EPR1eIJJkwDTsvap0ymL9pfIqMiLuiteH5kGmL/dyONy9oAJywLEeITfoVyElM/CY6Dc+xDhRnjN7Hu54meYyXRZrnCtQ3YhzEr1immNBn6npgA/qi9aHsuWFOw8b8aSwOHDHTDmjmvV+axI8CVMrR0MjB9QNCWrKLq2B9iQX9MtLgcUyDsQvzAsxUJm/OEfzUjs9SHvmgmyAvzNAuTdO7wLQ+ZmKg0yZne6nvcrJVvfh3lD5ZPt7NY57Y6OIJluqKUT5H+a3H6W9Q1Z+cBMnHGYaaK7Tv8IcDdEYqTIG8hc5BqjFOzE=";
@ -87,8 +73,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.True(Utilities.RSAUtility.VerifyWithSHA256ByCertificate(RSA_CERTIFICATE, plainText, signText));
}
[Fact(DisplayName = "使用 RSA 公钥加密")]
public void RSAEncryptTest()
[Fact(DisplayName = "测试用例:使用 RSA 公钥加密")]
public void TestRSAEncrypt()
{
string plainText = "RsaEncryptTest";
string actualCipherByPublicKey = Utilities.RSAUtility.EncryptWithECB(RSA_PUBLIC_KEY, plainText);
@ -99,8 +85,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotEqual(actualCipherByPublicKey, actualCipherByCertificate);
}
[Fact(DisplayName = "使用 RSA 私钥解密")]
public void RSADecryptTest()
[Fact(DisplayName = "测试用例:使用 RSA 私钥解密")]
public void TestRSADecrypt()
{
string cipherText = "LXwSqg4jqIv1X8Jx7RAbKw+mc/2SqAfdO4Ytqu09kytzCiDFdIZuJkdo2BQQOoyn/FtCyvn9Loip3VocOuATtsUDo6BmeMJcapl0HfXkyxsYnVRawsq01SPIRz8c83u+K38ZDVjNxEwcwcxH86wMm3PMzLZqISIVrD9sD3an5TfGuS+y/RN8y6W/P7BD/Rpxh0qLJl5B2oPYHOeKK0tdv6GlouUClzxB5tmdK5EKKw0j4WD5qIEwRm8Xzh/V27bt2autzRBbJT47eNypMR5wT7wWm/YwjyDoLLUmuCBaXbWZuqkB0pGS53y3Rdk64LVZ52567hBuQ/JdqMJdCecfy85x+ygnOtCM7bRl/fspU8U5SmwAKohYMc8VH4kRKhxoh8wX9wXCwbngLQ+S50TB3UziY1FmAmWFAI2/fpiyzGJZAVA+mYRCoQAFOksVEuud3ngGkfx2SafJ589IX9z0dnaz1AElaH84LhrOjJyU7dV6E9Su45IegNNai2O8bwN8dliVMPlXZuUAGaZpPLPOxq+hE7GpgNHaVFNye52b7dG3n3mt3hhSwb9AxAyAbSXktBSS/PMOAAS1TxwQ9C/0bKhApUDpjTG8oZBRBVTUHmsX+6/k5+6KSqfOrD88cBDPIhumY6V1h78GtXkFX2lQu9lT2J/fHCrDx39CiRnFAfI=";
string actualPlain = Utilities.RSAUtility.DecryptWithECB(RSA_PRIVATE_KEY, cipherText);
@ -108,16 +94,5 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.Equal(expectedPlain, actualPlain);
}
[Fact(DisplayName = "信息摘要SHA-256")]
public void SHA256HashTest()
{
string rawData = "SHA256HashTest";
string actualHash = Utilities.SHA256Utility.Hash(rawData);
string expectedHash = "8446f1ce5ca8b4a87c0d0cc15be4ba173b2ff78dc33c5f6731d877dcd2d8f401";
Assert.Equal(expectedHash, actualHash, ignoreCase: true);
}
}
}

View File

@ -7,14 +7,14 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
{
static TestClients()
{
GlobalCertificateManager = new Settings.InMemoryCertificateManager();
var certificateManager = new Settings.InMemoryCertificateManager();
Instance = new WechatTenpayClient(new WechatTenpayClientOptions()
{
MerchantId = TestConfigs.WechatMerchantId,
MerchantV3Secret = TestConfigs.WechatMerchantSecret,
MerchantCertSerialNumber = TestConfigs.WechatMerchantCertSerialNumber,
MerchantCertPrivateKey = TestConfigs.WechatMerchantCertPrivateKey,
CertificateManager = GlobalCertificateManager
CertificateManager = certificateManager
});
}
@ -26,12 +26,10 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
response = Instance.DecryptResponseSensitiveProperty(response);
foreach (var certificateModel in response.CertificateList)
{
GlobalCertificateManager.AddEntry(new Settings.CertificateEntry(certificateModel));
Instance.CertificateManager.AddEntry(new Settings.CertificateEntry(certificateModel));
}
}
public static readonly Settings.CertificateManager GlobalCertificateManager;
public static readonly WechatTenpayClient Instance;
}
}

View File

@ -17,15 +17,15 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
using var jdoc = JsonDocument.Parse(stream);
var config = jdoc.RootElement.GetProperty("TestConfig");
WechatAppId = config.GetProperty("AppId").GetString();
WechatMerchantId = config.GetProperty("MerchantId").GetString();
WechatMerchantSecret = config.GetProperty("MerchantSecret").GetString();
WechatMerchantCertSerialNumber = config.GetProperty("MerchantCertSerialNumber").GetString();
WechatMerchantCertPrivateKey = config.GetProperty("MerchantCertPrivateKey").GetString();
WechatOpenId = config.GetProperty("OpenId").GetString();
WechatMerchantId = config.GetProperty("MerchantId").GetString()!;
WechatMerchantSecret = config.GetProperty("MerchantSecret").GetString()!;
WechatMerchantCertSerialNumber = config.GetProperty("MerchantCertSerialNumber").GetString()!;
WechatMerchantCertPrivateKey = config.GetProperty("MerchantCertPrivateKey").GetString()!;
WechatAppId = config.GetProperty("AppId").GetString()!;
WechatOpenId = config.GetProperty("OpenId").GetString()!;
ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString();
ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString();
ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString()!;
ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString()!;
}
catch (Exception ex)
{
@ -33,11 +33,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
}
}
public static readonly string WechatAppId;
public static readonly string WechatMerchantId;
public static readonly string WechatMerchantSecret;
public static readonly string WechatMerchantCertSerialNumber;
public static readonly string WechatMerchantCertPrivateKey;
public static readonly string WechatAppId;
public static readonly string WechatOpenId;
public static readonly string ProjectSourceDirectory;

View File

@ -1,10 +1,10 @@
{
"TestConfig": {
"AppId": "请在此填写用于测试的微信 AppId",
"MerchantId": "请在此填写用于测试的微信商户号",
"MerchantSecret": "请在此填写用于测试的微信商户 API v3 密钥",
"MerchantCertSerialNumber": "请在此填写用于测试的微信商户 API 证书序列号",
"MerchantCertPrivateKey": "请在此填写用于测试的微信商户 API 证书私钥(字符串格式)",
"AppId": "请在此填写用于测试的微信 AppId",
"OpenId": "请在此填写用于测试的微信用户唯一标识"
},
"ProjectSourceDirectory": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.TenpayV3\\",