mirror of
https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git
synced 2026-03-10 00:13:36 +08:00
init commit
This commit is contained in:
1
test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/.gitignore
vendored
Normal file
1
test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
appsettings.local.json
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"ip_list": [ "127.0.0.1", "127.0.0.2", "101.226.103.0/25" ]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"ip_list": [ "127.0.0.1", "127.0.0.2", "101.226.103.0/25" ]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"errcode": 0,
|
||||
"errmsg": "ok",
|
||||
"ticket": "bxLdikRXVbTPdHSM05e5u5sUoXNKdvsdshFKA",
|
||||
"expires_in": 7200
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"access_token": "ACCESS_TOKEN",
|
||||
"expires_in": 7200
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"tag": {
|
||||
"name": "广东"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"tag": {
|
||||
"id": 134,
|
||||
"name": "广东"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"tag": {
|
||||
"id": 134
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"errcode": 0,
|
||||
"errmsg": "ok"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"tags": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "每天一罐可乐星人",
|
||||
"count": 0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "星标组",
|
||||
"count": 0
|
||||
},
|
||||
{
|
||||
"id": 127,
|
||||
"name": "广东",
|
||||
"count": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"tag": {
|
||||
"id": 134,
|
||||
"name": "广东人"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"errcode": 0,
|
||||
"errmsg": "ok"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"tagid": 134,
|
||||
"next_openid": ""
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"count": 2,
|
||||
"data": {
|
||||
"openid": [
|
||||
"ocYxcuAEy30bX0NXmGn4ypqx3tI0",
|
||||
"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"
|
||||
]
|
||||
},
|
||||
"next_openid": "ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"openid": "ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"tagid_list": [ 134, 2 ]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"openid_list": [
|
||||
"ocYxcuAEy30bX0NXmGn4ypqx3tI0",
|
||||
"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"
|
||||
],
|
||||
"tagid": 134
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"errcode": 0,
|
||||
"errmsg": "ok"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"openid_list": [
|
||||
"ocYxcuAEy30bX0NXmGn4ypqx3tI0",
|
||||
"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"
|
||||
],
|
||||
"tagid": 134
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"errcode": 0,
|
||||
"errmsg": "ok"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"openid_list": [ "OPENID1", "OPENID2" ]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"errcode": 0,
|
||||
"errmsg": "ok"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"openid_list": [ "OPENID1", "OPENID2" ]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"errcode": 0,
|
||||
"errmsg": "ok"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"begin_openid": "OPENID1"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"total": 23000,
|
||||
"count": 10000,
|
||||
"data": {
|
||||
"openid": [
|
||||
"OPENID1",
|
||||
"OPENID2",
|
||||
"OPENID10000"
|
||||
]
|
||||
},
|
||||
"next_openid": "OPENID10000"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"user_list": [
|
||||
{
|
||||
"openid": "otvxTs4dckWG7imySrJd6jSi0CWE",
|
||||
"lang": "zh_CN"
|
||||
},
|
||||
{
|
||||
"openid": "otvxTs_JZ6SEiP0imdhpi50fuSZg",
|
||||
"lang": "zh_CN"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"user_info_list": [
|
||||
{
|
||||
"subscribe": 1,
|
||||
"openid": "otvxTs4dckWG7imySrJd6jSi0CWE",
|
||||
"nickname": "iWithery",
|
||||
"sex": 1,
|
||||
"language": "zh_CN",
|
||||
"city": "揭阳",
|
||||
"province": "广东",
|
||||
"country": "中国",
|
||||
|
||||
"headimgurl": "http://thirdwx.qlogo.cn/mmopen/xbIQx1GRqdvyqkMMhEaGOX802l1CyqMJNgUzKP8MeAeHFicRDSnZH7FY4XB7p8XHXIf6uJA2SCunTPicGKezDC4saKISzRj3nz/0",
|
||||
|
||||
"subscribe_time": 1434093047,
|
||||
"unionid": "oR5GjjgEhCMJFyzaVZdrxZ2zRRF4",
|
||||
"remark": "",
|
||||
|
||||
"groupid": 0,
|
||||
"tagid_list": [ 128, 2 ],
|
||||
"subscribe_scene": "ADD_SCENE_QR_CODE",
|
||||
"qr_scene": 98765,
|
||||
"qr_scene_str": ""
|
||||
|
||||
},
|
||||
{
|
||||
"subscribe": 0,
|
||||
"openid": "otvxTs_JZ6SEiP0imdhpi50fuSZg"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"subscribe": 1,
|
||||
"openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M",
|
||||
"nickname": "Band",
|
||||
"sex": 1,
|
||||
"language": "zh_CN",
|
||||
"city": "广州",
|
||||
"province": "广东",
|
||||
"country": "中国",
|
||||
"headimgurl": "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
|
||||
"subscribe_time": 1382694957,
|
||||
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL",
|
||||
"remark": "",
|
||||
"groupid": 0,
|
||||
"tagid_list": [ 128, 2 ],
|
||||
"subscribe_scene": "ADD_SCENE_QR_CODE",
|
||||
"qr_scene": 98765,
|
||||
"qr_scene_str": ""
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"openid": "oDF3iY9ffA-hqb2vVvbr7qxf6A0Q",
|
||||
"remark": "pangzi"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"errcode": 0,
|
||||
"errmsg": "ok"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"total": 2,
|
||||
"count": 2,
|
||||
"data": {
|
||||
"openid": [ "OPENID1", "OPENID2" ]
|
||||
},
|
||||
"next_openid": "NEXT_OPENID"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"errcode": 0,
|
||||
"errmsg": "ok"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"openid": "OPENID",
|
||||
"unionid": "UNIONID",
|
||||
"session_key": "SESSION_KEY"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"access_token": "ACCESS_TOKEN",
|
||||
"expires_in": 7200,
|
||||
"refresh_token": "REFRESH_TOKEN",
|
||||
"openid": "OPENID",
|
||||
"scope": "SCOPE"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"access_token": "ACCESS_TOKEN",
|
||||
"expires_in": 7200,
|
||||
"refresh_token": "REFRESH_TOKEN",
|
||||
"openid": "OPENID",
|
||||
"scope": "SCOPE"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"openid": "OPENID",
|
||||
"nickname": "NICKNAME",
|
||||
"sex": 1,
|
||||
"province": "PROVINCE",
|
||||
"city": "CITY",
|
||||
"country": "COUNTRY",
|
||||
"headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
|
||||
"privilege": [ "PRIVILEGE1", "PRIVILEGE2" ],
|
||||
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove=".gitignore" />
|
||||
<Content Include="appsettings.json" />
|
||||
<Content Include="appsettings.local.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="ModelSamples/**/*.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SKIT.FlurlHttpClient.Wechat.Api\SKIT.FlurlHttpClient.Wechat.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
|
||||
{
|
||||
class TestClients
|
||||
{
|
||||
static TestClients()
|
||||
{
|
||||
Instance = new WechatApiClient(TestConfigs.WechatAppId, TestConfigs.WechatAppSecret);
|
||||
}
|
||||
|
||||
public static readonly WechatApiClient Instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
|
||||
{
|
||||
class TestConfigs
|
||||
{
|
||||
static TestConfigs()
|
||||
{
|
||||
// NOTICE: 请在项目根目录下建立 appsettings.local.json,按照 appsettings.json 的格式填入测试参数。
|
||||
// WARN: 敏感信息请不要提交到 git!
|
||||
|
||||
using var stream = File.OpenRead("appsettings.local.json");
|
||||
using var json = JsonDocument.Parse(stream);
|
||||
var config = json.RootElement.GetProperty("WechatConfig");
|
||||
WechatAppId = config.GetProperty("AppId").GetString();
|
||||
WechatAppSecret = config.GetProperty("AppSecret").GetString();
|
||||
WechatAccessToken = config.GetProperty("AccessToken").GetString();
|
||||
WechatOpenId = config.GetProperty("OpenId").GetString();
|
||||
}
|
||||
|
||||
public static readonly string WechatAppId;
|
||||
public static readonly string WechatAppSecret;
|
||||
public static readonly string WechatAccessToken;
|
||||
public static readonly string WechatOpenId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
|
||||
{
|
||||
public class WechatApiDefinitionTests
|
||||
{
|
||||
private static readonly Assembly _assembly = Assembly.Load("SKIT.FlurlHttpClient.Wechat.Api");
|
||||
|
||||
[Fact(DisplayName = "验证模型定义")]
|
||||
public void ModelDefinitionsTest()
|
||||
{
|
||||
static void SetPropertiesValueRecursively(object obj)
|
||||
{
|
||||
var lstProperty = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
foreach (var tProperty in lstProperty)
|
||||
{
|
||||
if (tProperty.SetMethod == null || !tProperty.SetMethod.IsPublic)
|
||||
continue;
|
||||
|
||||
if (tProperty.PropertyType.IsPrimitive)
|
||||
{
|
||||
// noop
|
||||
}
|
||||
else if (tProperty.PropertyType.IsArray)
|
||||
{
|
||||
Type tEl = tProperty.PropertyType.Assembly.GetType(tProperty.PropertyType.FullName.Replace("[]", string.Empty));
|
||||
object propEl = (tEl == typeof(string)) ? string.Empty : Activator.CreateInstance(tEl);
|
||||
propEl = Convert.ChangeType(propEl, tEl);
|
||||
SetPropertiesValueRecursively(propEl);
|
||||
|
||||
Array prop = Array.CreateInstance(tEl, 1);
|
||||
prop.SetValue(propEl, 0);
|
||||
|
||||
tProperty.SetValue(obj, prop);
|
||||
}
|
||||
else if (tProperty.PropertyType == typeof(string))
|
||||
{
|
||||
tProperty.SetValue(obj, string.Empty);
|
||||
}
|
||||
else if (tProperty.PropertyType.Namespace == "System" &&
|
||||
tProperty.PropertyType.Name.StartsWith("Nullable"))
|
||||
{
|
||||
// noop
|
||||
}
|
||||
else if (tProperty.PropertyType.Namespace == "System.Collections.Generic" &&
|
||||
(tProperty.PropertyType.Name.StartsWith("IDictionary") || tProperty.PropertyType.Name.StartsWith("Dictionary")))
|
||||
{
|
||||
// noop
|
||||
}
|
||||
else if (tProperty.PropertyType.Namespace == "System.Collections.Generic" &&
|
||||
(tProperty.PropertyType.Name.StartsWith("IList") || tProperty.PropertyType.Name.StartsWith("List")))
|
||||
{
|
||||
Type tGeneric = tProperty.PropertyType.GetGenericArguments().Single();
|
||||
object propEl = (tGeneric == typeof(string)) ? string.Empty : Activator.CreateInstance(tGeneric);
|
||||
propEl = Convert.ChangeType(propEl, tGeneric);
|
||||
SetPropertiesValueRecursively(propEl);
|
||||
|
||||
Type tList = typeof(List<>).MakeGenericType(new Type[] { tGeneric });
|
||||
object prop = Activator.CreateInstance(tList);
|
||||
|
||||
tList.GetMethod("Add").Invoke(prop, new[] { propEl });
|
||||
|
||||
tProperty.SetValue(obj, prop);
|
||||
}
|
||||
else
|
||||
{
|
||||
object prop = Activator.CreateInstance(tProperty.PropertyType);
|
||||
SetPropertiesValueRecursively(prop);
|
||||
|
||||
tProperty.SetValue(obj, prop);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var lstModel = _assembly.GetTypes()
|
||||
.Where(e =>
|
||||
e.Namespace != null &&
|
||||
e.Namespace.Equals(_assembly.GetName().Name + "Models") &&
|
||||
e.IsClass &&
|
||||
!e.IsAbstract &&
|
||||
!e.IsInterface &&
|
||||
!e.IsNested
|
||||
)
|
||||
.ToList();
|
||||
|
||||
var exceptions = new List<Type>();
|
||||
|
||||
foreach (Type tModel in lstModel)
|
||||
{
|
||||
// 模型命名结尾必为 Request 或 Response
|
||||
if (!tModel.Name.EndsWith("Request") && !tModel.Name.EndsWith("Response"))
|
||||
{
|
||||
exceptions.Add(tModel);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Request 必继承自 WechatApiRequest、且有同名 Response
|
||||
if (tModel.Name.EndsWith("Request"))
|
||||
{
|
||||
if (!typeof(WechatApiRequest).IsAssignableFrom(tModel))
|
||||
{
|
||||
exceptions.Add(tModel);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!lstModel.Any(e => e.Name == $"{tModel.Name.Substring(0, tModel.Name.Length - "Request".Length)}Response"))
|
||||
{
|
||||
exceptions.Add(tModel);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Request 必继承自 WechatApiResponse、且有同名 Request
|
||||
if (tModel.Name.EndsWith("Response"))
|
||||
{
|
||||
if (!typeof(WechatApiResponse).IsAssignableFrom(tModel))
|
||||
{
|
||||
exceptions.Add(tModel);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!lstModel.Any(e => e.Name == $"{tModel.Name.Substring(0, tModel.Name.Length - "Response".Length)}Request"))
|
||||
{
|
||||
exceptions.Add(tModel);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 递归构造模型,并尝试 JSON 序列化以检测是否有序列化问题
|
||||
try
|
||||
{
|
||||
object instance = _assembly.CreateInstance(tModel.Namespace + "." + tModel.Name);
|
||||
SetPropertiesValueRecursively(instance);
|
||||
|
||||
new FlurlNewtonsoftJsonSerializer().Serialize(instance);
|
||||
new FlurlSystemTextJsonSerializer().Serialize(instance);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Serialize `{tModel.Name}` failed.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.Empty(exceptions);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "验证接口定义")]
|
||||
public void InterfaceDefinitionsTest()
|
||||
{
|
||||
var lstInterface = _assembly.GetTypes()
|
||||
.Where(e =>
|
||||
e.Namespace != null &&
|
||||
e.Namespace.Equals(_assembly.GetName().Name) &&
|
||||
e.Name.StartsWith("WechatApiClientExecute") &&
|
||||
e.Name.EndsWith("Extensions")
|
||||
)
|
||||
.ToList();
|
||||
|
||||
var exceptions = new List<MethodInfo>();
|
||||
|
||||
foreach (Type tInterface in lstInterface)
|
||||
{
|
||||
var lstMethod = tInterface.GetMethods()
|
||||
.Where(e =>
|
||||
e.IsPublic &&
|
||||
e.IsStatic &&
|
||||
e.GetParameters().FirstOrDefault().ParameterType == typeof(WechatApiClient)
|
||||
)
|
||||
.ToList();
|
||||
foreach (MethodInfo tMethod in lstMethod)
|
||||
{
|
||||
var lstParam = tMethod.GetParameters();
|
||||
|
||||
// 参数签名必为 this client + request + cancelToken
|
||||
if (lstParam.Length != 3)
|
||||
{
|
||||
exceptions.Add(tMethod);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 第二个参数必为 WechatApiRequest 子类
|
||||
if (!typeof(WechatApiRequest).IsAssignableFrom(lstParam[1].ParameterType))
|
||||
{
|
||||
exceptions.Add(tMethod);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 方法名与第二个参数、返回值均有相同命名
|
||||
string func = tMethod.Name;
|
||||
string para = lstParam[1].ParameterType.Name;
|
||||
string retv = tMethod.ReturnType.GenericTypeArguments.FirstOrDefault()?.Name;
|
||||
if (para == null || !para.EndsWith("Request"))
|
||||
{
|
||||
exceptions.Add(tMethod);
|
||||
continue;
|
||||
}
|
||||
else if (retv == null || !retv.EndsWith("Response"))
|
||||
{
|
||||
exceptions.Add(tMethod);
|
||||
continue;
|
||||
}
|
||||
else if (!string.Equals(func, $"Execute{para.Substring(0, para.Length - "Request".Length)}Async"))
|
||||
{
|
||||
exceptions.Add(tMethod);
|
||||
continue;
|
||||
}
|
||||
else if (!string.Equals(func, $"Execute{retv.Substring(0, retv.Length - "Response".Length)}Async"))
|
||||
{
|
||||
exceptions.Add(tMethod);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert.Empty(exceptions);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "验证字段定义")]
|
||||
public void FieldDefinitionsTest()
|
||||
{
|
||||
static string[] GetFiles(string path)
|
||||
{
|
||||
var results = new List<string>();
|
||||
|
||||
string[] dirs = Directory.GetDirectories(path);
|
||||
string[] files = Directory.GetFiles(path);
|
||||
|
||||
results.AddRange(files);
|
||||
|
||||
foreach (string dir in dirs)
|
||||
{
|
||||
results.AddRange(GetFiles(dir));
|
||||
}
|
||||
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
string workdir = Path.Combine(Environment.CurrentDirectory, "ModelSamples");
|
||||
Assert.True(Directory.Exists(workdir));
|
||||
|
||||
var lstFile = GetFiles(workdir)
|
||||
.Where(e => string.Equals(Path.GetExtension(e), ".json", StringComparison.InvariantCultureIgnoreCase))
|
||||
.ToList();
|
||||
Assert.NotEmpty(lstFile);
|
||||
|
||||
var exceptions = new List<string>();
|
||||
|
||||
foreach (string file in lstFile)
|
||||
{
|
||||
string json = File.ReadAllText(file);
|
||||
string name = Path.GetFileNameWithoutExtension(file);
|
||||
|
||||
Type type = _assembly.GetType($"{_assembly.GetName().Name}.Models.{name}");
|
||||
if (type == null)
|
||||
{
|
||||
exceptions.Add(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var settings = FlurlNewtonsoftJsonSerializer.GetDefaultSerializerSettings();
|
||||
settings.CheckAdditionalContent = true;
|
||||
settings.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Error;
|
||||
new FlurlNewtonsoftJsonSerializer(settings).Deserialize(json, type);
|
||||
|
||||
new FlurlSystemTextJsonSerializer().Deserialize(json, type);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exceptions.Add(name);
|
||||
|
||||
if (ex is Newtonsoft.Json.JsonException)
|
||||
throw new Exception($"Deserialize `{name}` by Newtonsoft.Json failed.", ex);
|
||||
else if (ex is System.Text.Json.JsonException)
|
||||
throw new Exception($"Deserialize `{name}` by System.Text.Json failed.", ex);
|
||||
else
|
||||
throw new Exception($"Deserialize `{name}` failed.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.Empty(exceptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
|
||||
{
|
||||
public class WechatApiExecuteCgibinWithAccessTokenTests
|
||||
{
|
||||
[Fact(DisplayName = "[GET] /cgi-bin/ticket/getticket")]
|
||||
public async Task CgibinTicketGetTicketTest()
|
||||
{
|
||||
var request = new Models.CgibinTicketGetTicketRequest()
|
||||
{
|
||||
AccessToken = TestConfigs.WechatAccessToken
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteCgibinTicketGetTicketAsync(request);
|
||||
|
||||
Assert.NotNull(response.Ticket);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[GET] /cgi-bin/getcallbackip")]
|
||||
public async Task CgibinGetCallbackIpTest()
|
||||
{
|
||||
var request = new Models.CgibinGetCallbackIpRequest()
|
||||
{
|
||||
AccessToken = TestConfigs.WechatAccessToken
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteCgibinGetCallbackIpAsync(request);
|
||||
|
||||
Assert.NotEmpty(response.IPList);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[GET] /cgi-bin/get_api_domain_ip")]
|
||||
public async Task CgibinGetApiDomainIpTest()
|
||||
{
|
||||
var request = new Models.CgibinGetApiDomainIpRequest()
|
||||
{
|
||||
AccessToken = TestConfigs.WechatAccessToken
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteCgibinGetApiDomainIpAsync(request);
|
||||
|
||||
Assert.NotEmpty(response.IPList);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[GET] /cgi-bin/user/info")]
|
||||
public async Task CgibinUserInfoTest()
|
||||
{
|
||||
var request = new Models.CgibinUserInfoRequest()
|
||||
{
|
||||
AccessToken = TestConfigs.WechatAccessToken,
|
||||
OpenId = TestConfigs.WechatOpenId
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteCgibinUserInfoAsync(request);
|
||||
|
||||
Assert.NotEmpty(response.OpenId);
|
||||
Assert.NotEmpty(response.Nickname);
|
||||
Assert.True(response.Subscribe == 1);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[POST] /cgi-bin/user/info/batchget")]
|
||||
public async Task CgibinUserInfoBatchGetTest()
|
||||
{
|
||||
var request = new Models.CgibinUserInfoBatchGetRequest()
|
||||
{
|
||||
AccessToken = TestConfigs.WechatAccessToken,
|
||||
UserList = new Models.CgibinUserInfoBatchGetRequest.Types.User[]
|
||||
{
|
||||
new Models.CgibinUserInfoBatchGetRequest.Types.User() { OpenId = TestConfigs.WechatOpenId }
|
||||
}
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteCgibinUserInfoBatchGetAsync(request);
|
||||
|
||||
Assert.NotEmpty(response.UserList);
|
||||
Assert.NotEmpty(response.UserList.First().OpenId);
|
||||
Assert.NotEmpty(response.UserList.First().Nickname);
|
||||
Assert.True(response.UserList.First().Subscribe == 1);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[POST] /cgi-bin/user/info/updateremark")]
|
||||
public async Task CgibinUserInfoUpdateRemarkTest()
|
||||
{
|
||||
var request = new Models.CgibinUserInfoUpdateRemarkRequest()
|
||||
{
|
||||
AccessToken = TestConfigs.WechatAccessToken,
|
||||
OpenId = TestConfigs.WechatOpenId,
|
||||
Remark = "FAKE_REMARK"
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteCgibinUserInfoUpdateRemarkAsync(request);
|
||||
|
||||
Assert.Equal(0, response.ErrorCode);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[GET] /cgi-bin/user")]
|
||||
public async Task CgibinUserTest()
|
||||
{
|
||||
var request = new Models.CgibinUserRequest()
|
||||
{
|
||||
AccessToken = TestConfigs.WechatAccessToken
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteCgibinUserAsync(request);
|
||||
|
||||
Assert.NotEmpty(response.Data.OpenIdList);
|
||||
Assert.True(response.Total > 0);
|
||||
Assert.True(response.Count > 0);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[POST] /cgi-bin/tags/create")]
|
||||
public async Task CgibinTagsCreateTest()
|
||||
{
|
||||
var request = new Models.CgibinTagsCreateRequest()
|
||||
{
|
||||
AccessToken = TestConfigs.WechatAccessToken,
|
||||
Tag = new Models.CgibinTagsCreateRequest.Types.Tag()
|
||||
{
|
||||
Name = "FAKE_TAGNAME"
|
||||
}
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteCgibinTagsCreateAsync(request);
|
||||
|
||||
Assert.True(response.Tag.Id > 0);
|
||||
Assert.Equal(request.Tag.Name, response.Tag.Name);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[POST] /cgi-bin/tags/get")]
|
||||
public async Task CgibinTagsGetTest()
|
||||
{
|
||||
var request = new Models.CgibinTagsGetRequest()
|
||||
{
|
||||
AccessToken = TestConfigs.WechatAccessToken
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteCgibinTagsGetAsync(request);
|
||||
|
||||
Assert.NotEmpty(response.Tags);
|
||||
Assert.True(response.Tags.First().Id > 0);
|
||||
Assert.NotNull(response.Tags.First().Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
|
||||
{
|
||||
public class WechatApiExecuteCgibinWithAppSecretTests
|
||||
{
|
||||
[Fact(DisplayName = "[GET] /sns/cgi-bin/token")]
|
||||
public async Task CgibinTokenTest()
|
||||
{
|
||||
var request = new Models.CgibinTokenRequest();
|
||||
var response = await TestClients.Instance.ExecuteCgibinTokenAsync(request);
|
||||
|
||||
Assert.NotNull(response.AccessToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
|
||||
{
|
||||
public class WechatApiExecuteSnsWithAccessTokenTests
|
||||
{
|
||||
[Fact(DisplayName = "[GET] /sns/userinfo")]
|
||||
public async Task SnsUserInfoTest()
|
||||
{
|
||||
var request = new Models.SnsUserInfoRequest()
|
||||
{
|
||||
AccessToken = "FAKE_SNSACCESSTOKEN",
|
||||
OpenId = TestConfigs.WechatOpenId
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteSnsUserInfoAsync(request);
|
||||
|
||||
Assert.NotNull(response.OpenId);
|
||||
Assert.NotNull(response.Nickname);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[GET] /sns/auth")]
|
||||
public async Task SnsAuthTest()
|
||||
{
|
||||
var request = new Models.SnsAuthRequest()
|
||||
{
|
||||
AccessToken = "FAKE_SNSACCESSTOKEN",
|
||||
OpenId = TestConfigs.WechatOpenId
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteSnsAuthAsync(request);
|
||||
|
||||
Assert.Equal(0, response.ErrorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
|
||||
{
|
||||
public class WechatApiExecuteSnsWithAppSecretTests
|
||||
{
|
||||
[Fact(DisplayName = "[GET] /sns/oauth2/access_token")]
|
||||
public async Task SnsOAuth2AccessTokenTest()
|
||||
{
|
||||
var request = new Models.SnsOAuth2AccessTokenRequest()
|
||||
{
|
||||
Code = "FAKE_CODE"
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteSnsOAuth2AccessTokenAsync(request);
|
||||
|
||||
Assert.NotNull(response.AccessToken);
|
||||
Assert.NotNull(response.RefreshToken);
|
||||
Assert.NotNull(response.OpenId);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[GET] /sns/oauth2/refresh_token")]
|
||||
public async Task SnsOAuth2RefreshTokenTest()
|
||||
{
|
||||
var request = new Models.SnsOAuth2RefreshTokenRequest()
|
||||
{
|
||||
RefreshToken = "FAKE_REFRESHTOKEN"
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteSnsOAuth2RefreshTokenAsync(request);
|
||||
|
||||
Assert.NotNull(response.AccessToken);
|
||||
Assert.NotNull(response.RefreshToken);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "[GET] /sns/jscode2session")]
|
||||
public async Task SnsJsCode2SessionTest()
|
||||
{
|
||||
var request = new Models.SnsJsCode2SessionRequest()
|
||||
{
|
||||
JsCode = "FAKE_CODE"
|
||||
};
|
||||
var response = await TestClients.Instance.ExecuteSnsJsCode2SessionAsync(request);
|
||||
|
||||
Assert.NotNull(response.OpenId);
|
||||
Assert.NotNull(response.SessionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"WechatConfig": {
|
||||
"AppId": "请在此填写用于测试的微信 AppId",
|
||||
"AppSecret": "请在此填写用于测试的微信 AppSecret",
|
||||
"AccessToken": "请在此填写用于测试的微信 AccessToken",
|
||||
"OpenId": "请在此填写用于测试的微信用户唯一标识"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user