• Net6 Xunit 集成测试


            对于单元测试、集成测试大部分开发的朋友都懒得去写,因为这要耗费精力去设计去开发,做完项目模块直接postman 调用测试(当然这是一个选择,开发也中经常用到),但是如果测试需要多样化数据,各种场景模拟这样postman测试就暴露了他的局限性,下面我将Net6下没有使用Startup以及NET6以前版本使用Startup的集成测试(单元测试雷同)做一个梳理

    1.新建测试项目

     2.使用到的类库

    Xunti与xunit.runner.visualstudio创建测试项目是自带 

    Xunit.DependencyInjection 这是一个测试注入的扩展:github地址:https://github.com/pengweiqhca/Xunit.DependencyInjection

    Xunit.Extensions.Ordering 这是一个排序执行测试方法的扩展,因为有些方法是需要按照顺序执行,如获取图形验证码-->发送手机验证码-->到获取Token这是一个有序的过程,如果没有按照顺序执行肯定是不对的,github地址:https://github.com/tomaszeman/Xunit.Extensions.Ordering

    3.注入

      就是将要测试项目的所有注入重新注入测试项目(Program.cs)中和Startup中的所有东东全部注入,NET6中默认取消了Startup类,那么就要手工全部将这些注入再测试项目中添加一次,注入的时候有些是不兼容的做一下小的改动就行,因为https://github.com/pengweiqhca/Xunit.DependencyInjection的注入还是停留在NET5以下版本的,哦对了,还有中间件也是需要在测试项目中添加的,

    3.1 NET5 以下,测试项目中的Startup需要自己手工创建,区别在于NET5项目有Startup注入的时候不用手动写很多东西,测试项目直接从项目中的Startup查找注入,

     public class Startup
        {
            // custom host build
            public void ConfigureHost(IHostBuilder hostBuilder)
            {
                hostBuilder
                    .ConfigureHostConfiguration(builder =>
                    {
                        builder.AddJsonFile("appsettings.json", true);
                    })
                    .ConfigureWebHostDefaults(builder =>
                    {
                        builder.UseStartup<Dx.H5.Service.Startup>();//此处为项目中的startup,不是测试项目中的startup
    
                        builder.UseTestServer();
                        builder.ConfigureServices(services =>
                        {
                            services.AddSingleton(sp => sp.GetRequiredService<IHost>()
                                .GetTestClient()
                            );
                        });
                    })
                    ;
            }
            // add services need to injection
            // ConfigureServices(IServiceCollection services)
            // ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext)
            // ConfigureServices(HostBuilderContext hostBuilderContext, IServiceCollection services)
            public void ConfigureServices(IServiceCollection services)
            {
                // ready check
                //services.AddHostedService<ReadyCheckHostedService>();
    
            }
    
            public void Configure(ILoggerFactory loggerFactory, ITestOutputHelperAccessor outputHelperAccessor)
            {
                loggerFactory.AddProvider(new XunitTestOutputLoggerProvider(outputHelperAccessor));
            }
        }

    3.2 NET6 ,测试项目中的Startup需要自己手工创建,NET6 项目取消了Startup那么就需要手工搬移所有的注入,需要注意的是Startup中的ConfigureServices不支持重载,也就是你只能用一个

    ConfigureServices方法,见如下示例,还有测试日志的注入,但是在测试项目中使用ILogger<>好像是有问题的,有时日志不打印, 使用

    private readonly ITestOutputHelperAccessor _testOutputHelperAccessor; 替代ILogger<>,直接在测试类构造函数中注入就行

    public class Startup
        {
            const string DefaultCorsPolicyName = "Default";
            public void ConfigureHost(IHostBuilder hostBuilder) =>
                hostBuilder.ConfigureWebHost(webHostBuilder => webHostBuilder
                    .UseTestServer()
                    .Configure(Configure)
                    .UseUrls("http://*:17890","http://*:17880")
                
                    .ConfigureServices(services =>
                    {
                        
                        services.AddSingleton(sp => sp.GetRequiredService<IHost>()
                                .GetTestClient()
                            );
    
                    })
                    
                )
                .ConfigureAppConfiguration(lb => lb.AddJsonFile("appsettings.json", false, true));
    
    
            public void ConfigureServices(IServiceCollection services, HostBuilderContext context)
            {
    
                services.AddControllers();
                services.AddEndpointsApiExplorer();
                services.AddSwaggerGen();
                services.AddHttpClient();
    
    
            }
            public void Configure(ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor) =>
            loggerFactory.AddProvider(new XunitTestOutputLoggerProvider(accessor));
            ////public void ConfigureHost(IHostBuilder hostBuilder) { }
            //public void ConfigureServices(IServiceCollection services)
            //{
            //}
            //public IHostBuilder CreateHostBuilder(AssemblyName assemblyName) 
            //{
            //    return new HostBuilder();
            //}
            private void Configure(IApplicationBuilder app)
            {
                //if (app.Environment.IsDevelopment())
                //{
                //    app.UseSwagger();
                //    app.UseSwaggerUI();
                //}
                app.UseRouting();
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints
                    .MapControllers();
                    endpoints.MapGet("/hb/generatetoken", context =>
                    {
                        return context.Response.WriteAsync(GenerateToken(context));
                    });
                });
            }
            string GenerateToken(HttpContext httpContext)
            {
                return "dfdfdfdfd";
            }
        }

    public static IEnumerable<object?[]> ReadFile()
            {
                yield return new object[] { "123"};
                yield return new object[] { "456" };
            }
    
    

    4.创建测试类测试方法:

    需要注意的是api接口测试中url忽略host与端口,默认端口配置请查阅https://github.com/pengweiqhca/Xunit.DependencyInjection文档,UnitTest2中的测试方法是带有数据集合的测试方法,及测试方法是执行多次的,测试方法中的参数数据就是由MemberData(nameof(ReadFile)),其中数据方法ReadFile必须是 public static ReadFile要不然会有报错

    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Threading.Tasks;
    using Xunit;
    using Xunit.DependencyInjection;
    using Xunit.Extensions.Ordering;
    using static WebApiXunit.Controllers.WeatherForecastController;
    
    namespace Xunit.WebApiTest
    {
        [Order(1)]
        public class UnitTest1
        {
            private HttpClient _client;
            private ILogger<UnitTest1> _logger;
            //private readonly ITestOutputHelperAccessor _testOutputHelperAccessor;
            public UnitTest1(
                //ITestOutputHelperAccessor testOutputHelperAccessor
                ILogger<UnitTest1> logger,
                HttpClient client
                )
            {
                _logger = logger;
                _client = client;
            }
            [Order(1)]
            [Fact(DisplayName = "1")]
            public async Task Test1()
            {
                var c = new MyClass();
                c.Name = "1";
                c.Description = "e";
                using var request = new HttpRequestMessage(HttpMethod.Post, "WeatherForecast/hb/post/add");
                var content = JsonConvert.SerializeObject(c);
                request.Content = new StringContent(content);
                request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                var resp = await _client.SendAsync(request);
                //var resp=await _client.GetAsync("/hb/generatetoken");
                _logger.LogInformation("成功");
                if (resp.IsSuccessStatusCode)
                {
    
                    var str = await resp.Content.ReadAsStringAsync();
                    Assert.True(true);
                    return;
                }
                Assert.True(false);
            }
            [Order(2)]
            [Fact(DisplayName = "2")]
            public async Task Test2()
            {
                var c = new MyClass();
                c.Name = "1";
                c.Description = "e";
                using var request = new HttpRequestMessage(HttpMethod.Post, "WeatherForecast/hb/post/add");
                var content = JsonConvert.SerializeObject(c);
                request.Content = new StringContent(content);
                request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                var resp = await _client.SendAsync(request);
                //var resp=await _client.GetAsync("/hb/generatetoken");
    
                //_testOutputHelperAccessor.Output.WriteLine("");
                _logger.LogInformation("成功");
                if (resp.IsSuccessStatusCode)
                {
    
                    var str = await resp.Content.ReadAsStringAsync();
                    Assert.True(true);
                    return;
                }
                Assert.True(false);
            }
        }
        [Order(2)]
        public class UnitTest2
        {
            private HttpClient _client;
            private ILogger<UnitTest2> _logger;
            public UnitTest2(
    
                ILogger<UnitTest2> logger,
                HttpClient client
                )
            {
                _logger = logger;
                _client = client;
            }
    
            [Theory]
            [MemberData(nameof(ReadFile))]
            public async Task Test2(string name)
            {
                _logger.LogInformation(name);
                Assert.True(true);
            }
    
            public static IEnumerable<object?[]> ReadFile()
            {
                yield return new object[] { "123"};
                yield return new object[] { "456" };
            }
        }
    }

    5.排序执行测试方法:

    使用Xunit.Extensions.Ordering进行排序执行测试方法时:首先在测试项目中新建一个AssemblyInfo.cs加入如下内容,主要没有类名及命名空间,其中[assembly: TestFramework("Xunit.Extensions.Ordering.TestFramework", "Xunit.Extensions.Ordering")]是一个按照集合进行排序的使用,但是他与已有xunit assembly冲突,暂时么有找到解决方法,所以该排序功能暂时不支持,类中的[Order(2)]为第一优先级排序顺序,方法中的[Order(2)]即在类的顺序下再排序

    using Xunit;
    using Xunit.Extensions.Ordering;
    [assembly: CollectionBehavior(DisableTestParallelization = true)]
    //[assembly: TestFramework("Xunit.Extensions.Ordering.TestFramework", "Xunit.Extensions.Ordering")]
    [assembly: TestCaseOrderer("Xunit.Extensions.Ordering.TestCaseOrderer", "Xunit.Extensions.Ordering")]
    [assembly: TestCollectionOrderer("Xunit.Extensions.Ordering.CollectionOrderer", "Xunit.Extensions.Ordering")]

    using Xunit;
    using Xunit.Extensions.Ordering;
    [assembly: CollectionBehavior(DisableTestParallelization = true)]
    //[assembly: TestFramework("Xunit.Extensions.Ordering.TestFramework", "Xunit.Extensions.Ordering")]
    [assembly: TestCaseOrderer("Xunit.Extensions.Ordering.TestCaseOrderer", "Xunit.Extensions.Ordering")]
    [assembly: TestCollectionOrderer("Xunit.Extensions.Ordering.CollectionOrderer", "Xunit.Extensions.Ordering")]

    6.运行测试项目:

    在vs中运行测试项目中右键可以看到运行和调试测试项目运行比较简单,如果在服务器上需要使用dotnet test运行测试,注意配置文件要与服务器的匹配,将项目整体目录拷贝到服务器,cd 到测试项目目录下执行 dotnet test,有多少个接口瞬间测试完毕,而且在项目后续迭代更新的时候,只需要执行以下就可以测试所有的接口。

  • 相关阅读:
    分布式锁设计方案
    ACID/CAP/BASE 理论知识
    分布式ID设计方案
    perl代码调试
    文档型数据库设计模式-如何存储树形数据 [转]
    树形结构的数据库表Schema设计
    http协议相关
    HTTPS加密原理(转)
    VBA读写XML文件
    VBA 刷新数据透视表
  • 原文地址:https://www.cnblogs.com/rengke2002/p/16300480.html
Copyright © 2020-2023  润新知