news 2026/5/30 19:33:45

使用C#编写微信小程序(3)单元测试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用C#编写微信小程序(3)单元测试

单元测试使用C#的单元测试,一切与C#无关的平台统一使用接口,通过依赖注入和mock使用

案例: 微信小程序Storage单元测试

using System.Text.Json; using System.Threading.Tasks; using TsRoslyn.Core.Api; using TsRoslyn.Razor.Core; using XieYun.Application.Interfaces; namespace XieYun.Application.Services; // 微信api抽象为IWxApi。隔离js和C# public class LocalStore<T>(IWxApi wxApi) : IStore<T> where T : class { private bool IsInitialized { get; set; } private T? Data { get; set; } public async Task<T?> GetAsync() { if (IsInitialized) return Data; var storeDataString = await wxApi.GetStorageAsync(typeof(T).ToString()); T? result = null; if (storeDataString is not null) { result = JsonSerializer.Deserialize<T>(storeDataString); } Data = result; IsInitialized = true; return result; } public Task SetAsync(T value) { Data = value; IsInitialized = true; return wxApi.SetStorageAsync(typeof(T).ToString(), JsonSerializer.Serialize(value)); } }

接下来使用ai,生成单元测试用例

using System.Text.Json; using Moq; using TsRoslyn.Core.Api; using XieYun.Application.Services; namespace XieYun.Application.Test.Services; public class TestData { public required string Name { get; init; } public required int Value { get; init; } } [TestFixture] [TestOf(typeof(LocalStore<>))] public class LocalStoreTest { private Mock<IWxApi> _wxApiMock; private LocalStore<TestData> _localStore; [SetUp] public void Setup() { _wxApiMock = new Mock<IWxApi>(); _localStore = new LocalStore<TestData>(_wxApiMock.Object); } [Test] public async Task GetAsync_WhenNotInitializedAndNoStorageData_ReturnsNull() { // Arrange _wxApiMock.Setup(x => x.GetStorageAsync(typeof(TestData).ToString())) .ReturnsAsync((string?)null); // Act var result = await _localStore.GetAsync(); // Assert Assert.That(result, Is.Null); _wxApiMock.Verify(x => x.GetStorageAsync(typeof(TestData).ToString()), Times.Once); } [Test] public async Task GetAsync_WhenNotInitializedAndHasStorageData_ReturnsDeserializedData() { // Arrange var testData = new TestData { Name = "Test", Value = 123 }; var serializedData = JsonSerializer.Serialize(testData); _wxApiMock.Setup(x => x.GetStorageAsync(typeof(TestData).ToString())) .ReturnsAsync(serializedData); // Act var result = await _localStore.GetAsync(); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.Name, Is.EqualTo(testData.Name)); Assert.That(result.Value, Is.EqualTo(testData.Value)); _wxApiMock.Verify(x => x.GetStorageAsync(typeof(TestData).ToString()), Times.Once); } [Test] public async Task GetAsync_WhenAlreadyInitialized_ReturnsCachedDataWithoutApiCall() { // Arrange var testData = new TestData { Name = "Cached", Value = 456 }; _localStore.SetAsync(testData).Wait(); // Initialize and cache data // Act var result = await _localStore.GetAsync(); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.Name, Is.EqualTo(testData.Name)); Assert.That(result.Value, Is.EqualTo(testData.Value)); _wxApiMock.Verify(x => x.GetStorageAsync(It.IsAny<string>()), Times.Never); } [Test] public async Task SetAsync_SerializesDataAndStoresInApi() { // Arrange var testData = new TestData { Name = "New", Value = 789 }; string? storedValue = null; _wxApiMock.Setup(x => x.SetStorageAsync(typeof(TestData).ToString(), It.IsAny<string>())) .Callback<string, string>((_, value) => storedValue = value) .Returns(Task.CompletedTask); // Act await _localStore.SetAsync(testData); // Assert _wxApiMock.Verify(x => x.SetStorageAsync(typeof(TestData).ToString(), It.IsAny<string>()), Times.Once); var deserialized = JsonSerializer.Deserialize<TestData>(storedValue); Assert.That(deserialized, Is.Not.Null); Assert.That(deserialized.Name, Is.EqualTo(testData.Name)); Assert.That(deserialized.Value, Is.EqualTo(testData.Value)); } [Test] public async Task SetAsync_UpdatesCachedData() { // Arrange var initialData = new TestData { Name = "Initial", Value = 111 }; var newData = new TestData { Name = "Updated", Value = 222 }; await _localStore.SetAsync(initialData); // Act await _localStore.SetAsync(newData); var result = await _localStore.GetAsync(); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.Name, Is.EqualTo(newData.Name)); Assert.That(result.Value, Is.EqualTo(newData.Value)); } [Test] public async Task GetAsync_AfterSet_ReturnsCachedDataWithoutApiCall() { // Arrange var testData = new TestData { Name = "Cached", Value = 333 }; await _localStore.SetAsync(testData); // Act var result = await _localStore.GetAsync(); // Assert Assert.That(result, Is.Not.Null); _wxApiMock.Verify(x => x.GetStorageAsync(It.IsAny<string>()), Times.Never); } [Test] public async Task MultipleGets_OnlyFetchesFromApiOnce() { // Arrange var testData = new TestData { Name = "Test", Value = 444 }; var serializedData = JsonSerializer.Serialize(testData); _wxApiMock.Setup(x => x.GetStorageAsync(typeof(TestData).ToString())) .ReturnsAsync(serializedData); // Act await _localStore.GetAsync(); await _localStore.GetAsync(); await _localStore.GetAsync(); // Assert _wxApiMock.Verify(x => x.GetStorageAsync(typeof(TestData).ToString()), Times.Once); } }

这样子就可以很轻松的使用C#的原生能力,进行测试。

应用项目里通过依赖注入,就能把js注入进来

serviceCollection.AddSingleton<IWxApi, WxApi>(); serviceCollection.AddSingleton<IStore<UserInfoStoreData>, LocalStore<UserInfoStoreData>>();
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 23:34:54

【收藏】Java程序员转型AI大模型:从入门到进阶的全攻略

在AI大模型技术席卷各行各业的当下&#xff0c;传统Java程序员面临着职业发展的新抉择——是坚守原有技术赛道&#xff0c;还是抓住机遇切入大模型领域实现职业升级&#xff1f;答案显而易见&#xff0c;转型AI大模型不仅能突破技术瓶颈&#xff0c;更是提升职业竞争力、实现薪…

作者头像 李华
网站建设 2026/5/31 2:58:54

NAS读取延时问题深度解析:NFS缓存机制与优化实战

在分布式存储场景中&#xff0c;NAS设备通过NFS协议实现多客户端共享访问时&#xff0c;常遇到文件更新后其他客户端无法立即感知的延迟问题。本文结合真实案例与技术原理&#xff0c;系统解析NFS缓存机制对数据一致性的影响&#xff0c;并提供可落地的优化方案。一、典型问题场…

作者头像 李华
网站建设 2026/5/30 20:51:54

Linux swap分区设置对Qwen3-32B内存溢出的影响

Linux swap分区设置对Qwen3-32B内存溢出的影响 在AI模型部署一线&#xff0c;你可能遇到过这样的场景&#xff1a;一台配置64GB内存的服务器上启动Qwen3-32B推理服务&#xff0c;刚加载完模型就触发OOM Killer&#xff0c;进程被无情终止。查看日志发现&#xff0c;系统明明还有…

作者头像 李华
网站建设 2026/5/31 3:26:36

生态重构:GEO视野下的未来信息传播链变革

GEO的兴起&#xff0c;远不止是一种营销技术的迭代。它像一股暗流&#xff0c;正在深刻重构从信息生产、传播到消费的全链条&#xff0c;催生一个全新的信息生态系统。理解这一系统性变革&#xff0c;才能把握GEO真正的战略高度。一、链条重塑&#xff1a;从“发布-索引-排名”…

作者头像 李华
网站建设 2026/5/26 2:09:09

LobeChat主题自定义教程:打造品牌专属AI界面

LobeChat主题自定义教程&#xff1a;打造品牌专属AI界面 在企业纷纷拥抱大模型的今天&#xff0c;一个共性问题浮现出来&#xff1a;市面上的AI对话工具虽然功能强大&#xff0c;但清一色的“通用面孔”难以承载品牌形象。用户打开客服窗口时&#xff0c;看到的不是冷冰冰的默认…

作者头像 李华