创建测试项目

项目解决方案上右键,添加---->新建项目,选择适合自己的测试项目,点击【下一步】。我选的xUnit
在这里插入图片描述

UnitTest1.cs单元测试类,创建项目后,自动生成的



using HL.Web.Api;
using HL.Web.Api.Services;
using HL.Web.Platform.Configure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Configuration;
using System.Reflection;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Logging.Debug;
using NLog.Web;
using NLog.Extensions.Logging;
using System.Diagnostics;
using HL.Web.Api.Entity.Model.Collect;
using HL.Web.Api.Services.Impl;
using SqlSugar;
using System.Threading.Tasks;

namespace TestProject1
{
    /// <summary>
    /// 单元测试
    /// </summary>
    /// <remarks>
    /// 创建2025-6-17 17:25:43,作者:王浩力
    /// </remarks>
    public class UnitTest1
    {
        private readonly IServiceProvider serviceProvider;

        public UnitTest1()
        {
            serviceProvider = CommInject.InitIoc();

        }


        /// <summary>
        /// 采集测试,写入数据
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task Test1()
        {
            //// 从容器中获取日志记录器,测试无效无法记录日志
            var logger = serviceProvider.GetRequiredService<ILogger<UnitTest1>>();
            //var logger = serviceProvider.GetService<ILogger<UnitTest1>>();
            logger.LogInformation("测试消息");
            //logger.LogDebug("测试消息2");

            //无效
            //var loggerFactory = LoggerFactory.Create(loggingBuilder => loggingBuilder
            //.AddConfiguration(configuration)
            //.AddConsole());
            //ILogger logger2 = loggerFactory.CreateLogger<UnitTest1>();
            //logger2.LogInformation("测试消息3");

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            LogHelpter.AddLog("任务开始....");

            //var task1 = Task.Run(async () =>
            //{
            //    var collectionData = serviceProvider.GetService<ICollectionData>();
            //    await collectionData.InsertTestAsync(DateTime.Now.AddDays(-3));
            //});
            //var task2 = Task.Run(async () =>
            //{
            //    var collectionData = serviceProvider.GetService<ICollectionData>();
            //    await collectionData.InsertTestAsync(DateTime.Now.AddDays(-2));
            //});
            var task3 = Task.Run(async () =>
            {
                var collectionDataService = serviceProvider.GetService<ICollectionDataService>();
                await collectionDataService.InsertTestAsync(DateTime.Now.AddDays(0));
            });
            //Task.WaitAll(task1, task2, task3);
            //Task.WaitAll(task1,    task3);
            Task.WaitAll(task3);

            stopwatch.Stop();
            float seconds = stopwatch.ElapsedMilliseconds / 1000;
            System.Diagnostics.Debug.WriteLine("任务完成,耗时秒=" + seconds);
            LogHelpter.AddLog("任务完成,耗时秒=" + seconds);
        }
 
        /// <summary>
        /// 单条写入
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task Insert()
        {
            var collectionDataService = serviceProvider.GetService<ICollectionDataService>();
            SinterEquipmentCollect info = new SinterEquipmentCollect();
            info.SingleId = 756;
            info.SingleName = "测试设备" + info.SingleId;
            long snowId = await collectionDataService.InsertAsync(info);
            Assert.Equal(snowId.ToString().Length, 19);
        }

        /// <summary>
        /// 批量写入
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task InsertList()
        {
            var collectionDataService = serviceProvider.GetService<ICollectionDataService>();

            List<SinterEquipmentCollect> list = new();
            for (int i = 0; i < 10; i++)
            {
                SinterEquipmentCollect info = new SinterEquipmentCollect();
                info.SingleId = 100 + i;
                info.SingleName = "测试设备" + info.SingleId;
                list.Add(info);
            }

            int count = await collectionDataService.InsertListAsync(list);
            Assert.True(count > 0);
        }
 

        [Fact]
        private async Task AddEquipmentData()
        {
            //测试,写入,每分钟一次,更新设备数据;每台设备一条记录;
            var equipmentService = serviceProvider.GetService<IEquipmentData>();
            // await equipmentService.AddDataEquipmentCurrentDataAsync();
            await equipmentService.AddEquipmentHistoryDataAsync();
        }


    }
}

怎么调试自己写的单元测试方法?

首先找到自己写的方法代码,鼠标点中方法代码段内,然后鼠标右键,可以点击(调试测试),就单独测试鼠标光标选中的方法;调试模式会命中打的断点;运行测试不会命中断点;

在这里插入图片描述

怎么测试一个单元测试类文件里面所有单元测试方法?

测试完成后,方法左侧标记的绿色勾,表示方法通过测试;否则没有通过测试;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

举例的接口实例,类头部加了自定义的属性标记ServiceAttribute

 /// <summary>
 /// 采集数据,接口实现
 /// </summary>
 /// <remarks>
 /// 创建时间:2025-6-17 15:30:46,作者:whl
 /// </remarks>
 [Service]
 public class CollectionDataService : ICollectionDataService
 {
     private readonly ISqlSugarClient sugarClient;

     public CollectionDataService(ISqlSugarClient _sqlSugarClient)
     {
         sugarClient = _sqlSugarClient;
     }
}


namespace HL.Web.Api
{
    /// <summary>
    /// 服务特性。 
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class ServiceAttribute : Attribute
    {
       
        /// <summary>
        /// 无参构造函数 
        /// </summary>
        public ServiceAttribute()
        {        
        }
 
    }
}

InjectUtil.cs

 using HL.Web.Api;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestProject1
{
    /// <summary>
    /// 依赖注入,工具
    /// </summary>
    /// <remarks>
    /// 创建时间:2025-6-17 16:36:43,作者:王浩力
    /// </remarks>
    public sealed class InjectUtil
    {
        /// <summary>
        /// 自动注册接口、实例
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceLifetime"></param>
        public static void InitServe(ServiceCollection services, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
        {
        //这里可以使用自己的方式找到接口、实例的类集合。不一定非要在实现类上面打自定义属性标签。
        //也可以通过类名的后缀查找类,或者类的命名空间查找等方式;
        //比如实现类后缀为impl结尾,则可以用类名后缀查找;
            List<Type> implList = AppDomain.CurrentDomain
                     .GetAssemblies()
                     .SelectMany(x => x.GetTypes())
                     .Where(w => w.GetCustomAttributes(typeof(ServiceAttribute), false).Length > 0
                            && w.IsClass && w.IsAbstract != true)
                     .ToList();

            foreach (Type impl in implList)
            {
                Type[] interfaces = impl.GetInterfaces();
                interfaces.ToList().ForEach(interfaceT =>
                {
                    switch (serviceLifetime)
                    {
                        case ServiceLifetime.Singleton:
                            services.AddSingleton(interfaceT, impl);
                            break;

                        case ServiceLifetime.Scoped:
                            services.AddScoped(interfaceT, impl);
                            break;

                        case ServiceLifetime.Transient:
                            services.AddTransient(interfaceT, impl);
                            break;
                    }
                });
            }
        }
    }
}


CommInject

using HL.Web.Platform.Configure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestProject1
{
    /// <summary>
    /// 依赖注入初始化
    /// </summary>
    /// <remarks>
    /// 创建时间:2025-6-18 17:53:09,王浩力
    /// </remarks>
    internal class CommInject
    {
        
       
        /// <summary>
        /// 初始化容器
        /// </summary>
        /// <returns></returns>
        public static IServiceProvider InitIoc()
        {
            IConfiguration configuration=null;

            //获取web项目的appsettings.json文件路径
            string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
            string bin = currentDirectory.Substring(0, currentDirectory.LastIndexOf("bin"));
            bin = bin.TrimEnd('\\');

            //解决方案目录
            string slnProject = Directory.GetParent(bin).FullName;

            var dir = Directory.GetDirectories(slnProject);
            string? configJsonfilePath = null;
            foreach (var item in dir)
            {
                var files = Directory.GetFiles(item);
                if (files.Length == 0)
                {
                    continue;
                }                
                string jsonName = $"appsettings.Development.json";
#if (!DEBUG) 
                jsonName = $"appsettings.Staging.json";
#endif
                LogHelpter.AddLog("配置文件="+ jsonName);
                configJsonfilePath = files.FirstOrDefault(g => g.Contains(jsonName));
                if (!string.IsNullOrWhiteSpace(configJsonfilePath))
                {
                    break;
                }
            }

            //加载配置文件
            configuration = new ConfigurationBuilder()
          .AddJsonFile(configJsonfilePath)
            .Build();

            ServiceCollection serviceCollection = new ServiceCollection();
            //ConfigureServices.AddServices(serviceCollection);
            ConfigureServices.AddSqlsugarSetup(serviceCollection, configuration);

            serviceCollection.AddLogging(builder =>
            {
                builder.ClearProviders();
                builder.AddConsole();
                builder.AddDebug();
                //builder.SetMinimumLevel(LogLevel.Debug);
                //builder.AddFilter("Logs/log_{Date}.txt"); // 注册 File 提供程序

            });
            serviceCollection.AddNLog();//日志组件实例

            //自动注册接口、实例
            InjectUtil.InitServe(serviceCollection);

            return serviceCollection.BuildServiceProvider();
        }

    }
}

ConfigureServices.cs

using System.Reflection;
using HL.Model.Attributes;
using HL.Web.Api;
using HL.Web.Api.Common.Consts;
using HL.Web.Api.JobServices;
using HL.Web.Platform.Filter;
using Quartz;
using SqlSugar;

namespace HL.Web.Platform.Configure
{
    /// <summary>
    /// 配置服务
    /// </summary>
    public static class ConfigureServices
    {
         

        /// <summary>
        /// 添加SqlSugar
        /// </summary>
        /// <param name="services"></param>
        /// <param name="config"></param>
        public static void AddSqlsugarSetup(this IServiceCollection services, IConfiguration config)
        {
            //读取数据库连接
            var collectDbConn = config.GetSection(DbConnectionConst.CollectDbConn).Value;
            var analysisDbConn = config.GetSection(DbConnectionConst.AnalysisDbConn).Value;

            //注入事务过滤器
            services.AddScoped<TransactionFilter>();

            //注册上下文:AOP里面可以获取IOC对象,如果有现成框架比如Furion可以不写这一行
            services.AddHttpContextAccessor();

            //实体、字段映射
            ConfigureExternalServices configureExternalServices = new ConfigureExternalServices
            {
                EntityService = (property, column) =>
                {
                    var ColumnInfo = property.GetCustomAttribute<ColumnInfoAttribute>();
                    if (ColumnInfo != null)
                    {
                        column.IsPrimarykey = ColumnInfo.IsPrimarykey;
                        column.DbColumnName = ColumnInfo.DbColumnName;
                        column.ColumnDescription = ColumnInfo.ColumnDescription;
                        column.IsNullable = ColumnInfo.IsNullable;
                        column.IsOnlyIgnoreUpdate = ColumnInfo.IsOnlyIgnoreUpdate;
                        column.IsJson = ColumnInfo.IsJson;
                        column.DataType = ColumnInfo.DataType;
                        column.SqlParameterDbType = ColumnInfo.SqlParameterDbType;
                        column.IsEnableUpdateVersionValidation = ColumnInfo.IsEnableUpdateVersionValidation;
                        column.IsIgnore = ColumnInfo.IsIgnore;
                        column.Length = ColumnInfo.Length;
                    }
                    else
                    {
                        //最好排除DTO类
                        column.DbColumnName = UtilMethods.ToUnderLine(column.DbColumnName);//ToUnderLine驼峰转下划线方法
                        column.IsNullable = true;
                    }
                },
                EntityNameService = (type, entity) =>
                {
                    var tableInfo = type.GetCustomAttribute<TableInfoAttribute>();
                    if (tableInfo != null)
                    {
                        entity.DbTableName = tableInfo.DbTableName;
                        entity.TableDescription = tableInfo.TableDescription;
                    }
                    else
                    {
                        //最好排除DTO类
                        entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName);//ToUnderLine驼峰转下划线方法
                    }
                }
            };

            //注册SqlSugar
            services.AddTransient<ISqlSugarClient>(client =>
            {
                SqlSugarScope sqlSugar = new SqlSugarScope(new List<ConnectionConfig>
                {
                    new ConnectionConfig(){ ConfigId = DbConnectionConst.CollectDbConn, DbType = DbType.SqlServer, ConnectionString = collectDbConn, IsAutoCloseConnection = true, ConfigureExternalServices = configureExternalServices },
                    new ConnectionConfig(){ ConfigId = DbConnectionConst.AnalysisDbConn, DbType = DbType.SqlServer, ConnectionString = analysisDbConn, IsAutoCloseConnection = true, ConfigureExternalServices = configureExternalServices }
                }
                ,
                db =>
                {
                    var serviceBuilder = services.BuildServiceProvider();
                    var logger = serviceBuilder.GetService<ILogger<ApiControllerBase>>();
                    //SQL执行完
                    db.Aop.OnLogExecuted = (sql, pars) =>
                    {
                        //执行完了可以输出SQL执行时间 (OnLogExecutedDelegate)
                        logger?.LogInformation($"ExecutedTime:{db.Ado.SqlExecutionTime}");

                        string sql2 = UtilMethods.GetNativeSql(sql, pars);
                        LogHelpter.AddLog($"{sql2}" );
                    };
                    //单例参数配置,所有上下文生效
                    db.Aop.OnLogExecuting = (sql, pars) =>
                    {
                        ////获取作IOC作用域对象
                        //var appServive = s.GetService<IHttpContextAccessor>();
                        //var obj = appServive?.HttpContext?.RequestServices.GetService<ILogger>();
                        //Console.WriteLine("AOP" + obj?.GetHashCode());

                        sql = UtilMethods.GetNativeSql(sql, pars);
                        logger?.LogInformation(sql);
                    };
                    db.Aop.OnError = (exp) =>//SQL报错
                    {
                        //获取原生SQL推荐 5.1.4.63  性能OK
                        UtilMethods.GetNativeSql(exp.Sql, exp.Parametres as SugarParameter[]);
                    };
                    db.Aop.OnExecutingChangeSql = (sql, pars) => //可以修改SQL和参数的值
                    {
                        //sql=newsql
                        //foreach(var p in pars) //修改
                        return new KeyValuePair<string, SugarParameter[]>(sql, pars);
                    };
                    db.Aop.DataExecuting = (oldValue, entityInfo) =>
                    {
                    };
                });
                return sqlSugar;
            });
        }

       
    }
}

更多推荐