首页 > 解决方案 > .net 核心集成测试:API 控制器操作未从测试中调用。如何在测试项目中模拟 opeind 连接身份验证?

问题描述

启动 cs 文件 .net core:(在创建测试服务器时也会调用它)

 public class Startup
{
    private IHostingEnvironment env;
    private Dictionary<string, string> secretlist = new Dictionary<string, string>();

    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {         
        this.Configuration = configuration;
        this.CurrentEnvironment = env;

    }

    public Startup(IHostingEnvironment env)
    {
        this.env = env;
    }

    public IConfiguration Configuration { get; }

    private IHostingEnvironment CurrentEnvironment { get; set; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<FormOptions>(x =>
        {
            x.ValueLengthLimit = int.MaxValue;
            x.MultipartBodyLengthLimit = int.MaxValue;
            x.MultipartHeadersLengthLimit = int.MaxValue;
        });

        services.AddApplicationInsightsTelemetry(this.Configuration);
        services.AddSingleton<ITelemetryInitializer, AppInsightsInitializer>();

        // Adds services required for using options.
        services.AddOptions();

        services.Configure<AppSettingsConfig>(this.Configuration.GetSection("AppSettings"));

        if (this.CurrentEnvironment.IsDevelopment())
        {
            services.AddDataProtection()
               .PersistKeysToFileSystem(new DirectoryInfo(Environment.ExpandEnvironmentVariables(this.Configuration.GetValue<string>("AppSettings:KeyStorage_UNCPath"))))
               .ProtectKeysWithDpapiNG();
        }
        else
        {
            CloudStorageAccount storageAccount = new CloudStorageAccount(
                new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(
                                                 this.Configuration.GetValue<string>("AppSettings:StorageAccountName"),
                                                this.Configuration.GetValue<string>("AppSettings:StorageAccessValue")), true);

            //Create blob client
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            // Get a reference to a container named "keycontainer."
            CloudBlobContainer container = blobClient.GetContainerReference("keycontainer");
            services.AddDataProtection().PersistKeysToAzureBlobStorage(container, "keys.xml");
        }

        services.Configure<AppSettingsConfig>(options =>
        {
            if (!this.CurrentEnvironment.IsDevelopment())
            {

            }
        });

        var azureAdConfig = new AzureAdConfig();
        this.Configuration.GetSection("Authentication:AzureAd").Bind(azureAdConfig);
        services.Configure<AzureAdConfig>(this.Configuration.GetSection("Authentication:AzureAd"));

        var connectionStringsConfig = new ConnectionStringsConfig();
        connectionStringsConfig.oneConnection = this.secretlist["ConnectionStrings"];
        //this.Configuration.GetSection("ConnectionStrings").Bind(connectionStringsConfig);
        //services.Configure<ConnectionStringsConfig>(this.Configuration.GetSection("ConnectionStrings"));



        if (this.RequireAAD())
        {
            // Add framework services.
            services.Configure<MvcOptions>(options =>
            {
                options.Filters.Add(new RequireHttpsAttribute());
            });
        }
        else
        {
            services.Configure<MvcOptions>(options =>
            {
            });
        }

        // Add Authentication services.
        if (this.RequireAAD())
        {
            // Configure the OWIN pipeline to use cookie auth.
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddCookie()
            // Configure the OWIN pipeline to use OpenID Connect auth.
            // https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-openid-connect-code
            .AddOpenIdConnect(options =>
            {
                options.ClientId = azureAdConfig.ClientId;
                options.ClientSecret = azureAdConfig.ClientSecret;
                options.Authority = string.Format(azureAdConfig.AADInstance, azureAdConfig.Tenant);
                options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
                options.Resource = azureAdConfig.ResourceURI_Graph;
                // PostLogoutRedirectUri = Configuration["AzureAd:PostLogoutRedirectUri"],
                options.Events = new AuthEvents(azureAdConfig, connectionStringsConfig);
            });




        if (this.RequireAAD())
        {
            services.AddMvc(config =>
            {
                var policy = new AuthorizationPolicyBuilder()
                                 .RequireAuthenticatedUser()
                                 .Build();
                config.Filters.Add(new Microsoft​.AspNetCore​.Mvc​.Authorization.AuthorizeFilter(policy));
                config.Filters.Add(typeof(ExceptionFilter));
            });
        }
        else
        {
            services.AddMvc();
        }
        if (this.Configuration.GetValue<bool>("API: SWITCH_ENABLE_API", true))
        {
            //services.AddScoped<IDBOperation, Operations>();
            services.AddScoped<ILookupSearch, Operations>();
            services.AddScoped<IFullSearch, Operations>();
        }

        services.AddSingleton<Common.Data.RepositoryFactories>(new Common.Data.RepositoryFactories(new Dictionary<Type, Func<DbContext, object>>
            {
                { typeof(IQueryRepository), dbcontext => new QueryRepository(dbcontext) },
                { typeof(IDomainValuesRepository), dbcontext => new DomainValuesRepository(dbcontext) },
                { typeof(IRequestsRepository), dbcontext => new RequestsRepository(dbcontext) },

                // { typeof(IoneDomainValuesRepository), dbcontext => new oneDomainValuesRepository(dbcontext) }
        }));

        services.AddTransient<Common.Contracts.IRepositoryProvider, Common.Data.RepositoryProvider>();
        services.AddScoped<one.Data.Contracts.IoneUow, one.Data.oneUow>();
        services.AddTransient<IUow,Uow>();
        // For accessing appinsights for dependency injection?
        services.AddApplicationInsightsTelemetry();

        // For Storing Tokens in DB
        services.AddDistributedSqlServerCache(o =>
        {
            o.ConnectionString = this.secretlist["ConnectionStrings"];
           // o.ConnectionString = this.Configuration.GetConnectionString("oneConnection");
            // o.ConnectionString = this.Configuration[this.Configuration.GetSection("KeyVaultSeetings")["oneConnectionString"]];
            o.SchemaName = "dbo";
            o.TableName = "CacheTable";
        });
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<IEntityExtractor, EntityExtractor>();
        services.AddScoped<ITokenCacheService, DistributedTokenCacheService>();
        services.AddScoped<ITokenService, TokenService>();
        services.AddTransient<IAPIClient,APIClient>();
    }

    /// <summary>
    ///  This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    /// <param name="loggerFactory"></param>
    /// <param name="tc"></param>
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, TelemetryClient tc)
    {
        var azureAdConfig = new AzureAdConfig();
        this.Configuration.GetSection("Authentication:AzureAd").Bind(azureAdConfig);
        loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
        loggerFactory.AddProvider(new MyFilteredLoggerProvider(tc));
        loggerFactory.AddApplicationInsights(app.ApplicationServices, this.Configuration.GetValue<string>("Logging:LogLevel:Default") == "Information" ? Microsoft.Extensions.Logging.LogLevel.Information : Microsoft.Extensions.Logging.LogLevel.Warning);

        this.SetupStore(app);

        app.UseRewriter(new RewriteOptions().AddRedirectToHttps());

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
            {
                HotModuleReplacement = true
            });
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        // TODO . Switch
        app.UseStaticFiles();

        if (this.RequireAAD())
        {
            app.UseAuthentication();
        }

        app.UseMiddleware(typeof(ErrorHandlingMiddleware));
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });
    }

}

控制器装饰为:

 [Route("api/[controller]")]
    public class SearchController : BaseController

控制器动作被装饰为:

[Route("TestMethod")]
        [ActionName("TestMethod")]
        [HttpGet]
        public async Task<EmptyResult> Test()

TestServer 测试 CS 文件的配置:

    public DemoTest()
     {
        // Set up server configuration
        var configuration = new ConfigurationBuilder()                                                              
                            .AddJsonFile(@"appsettings.json")
                            .Build();
        // Create builder
        var builder = new WebHostBuilder()                                                     
                        .UseStartup<Startup>()
                        .UseConfiguration(configuration);
        // Create test server
        var server = new TestServer(builder);
        // Create database context
        this._context = server.Host.Services.GetService(typeof(DBContext)) as DBContext;

        // Create client to query server endpoints
        this._client = server.CreateClient();
        _client.BaseAddress = new Uri("https://localhost:44316/");
}

测试为事实:

  [Fact]
    public async Task Test()
    {
        try
        {

            var response = await this._client.GetAsync("/api/Search/TestMethod");
            response.EnsureSuccessStatusCode();
            var responseString = await response.Content.ReadAsStringAsync();
            //Assert.False(result != null);
        }
        catch (Exception ex)
        {
            throw;
        }

    }

获取状态为 302 并且 SearchController 操作未被调用。使用启动配置文件解决所有依赖项

任何想法 ???

标签: c#.net.net-coreopenidopenid-connect

解决方案


您可以检查内容var responseString = await response.Content.ReadAsStringAsync();以查看内容是什么。

我认为这是由于您需要的登录页面Authorize

首先,尝试删除下面的代码进行尝试。

services.AddMvc(config =>
        {
            //var policy = new AuthorizationPolicyBuilder()
                             .RequireAuthenticatedUser()
                             .Build();
            //config.Filters.Add(new Microsoft​.AspNetCore​.Mvc​.Authorization.AuthorizeFilter(policy));
            config.Filters.Add(typeof(ExceptionFilter));
        });

对于Authentication,您将需要模拟登录过程,这是 Identity 的链接,您可以尝试为 AAD 实现自己的登录。

Razor Pages .NET Core 2.1 集成测试后身份验证


推荐阅读