我正在使用abp 3.9.0设置Web UI的集成测试。
所有内容都可以编译并执行,但是在我的Test基类中,以下内容会出现空引用异常:
protected void UsingDbContext(Action<CentralPortalDbContext> action)
{
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
action(context);
context.SaveChanges();
}
}
在调试过程中检查该函数,它表明IocManager为空。
我在所有类中尝试了各种排列,但是没有运气。
Startup.cs:
using System;
using Abp.AspNetCore;
using Abp.AspNetCore.TestBase;
using Abp.Dependency;
using *****.CentralPortal.EntityFrameworkCore;
using *****.CentralPortal.Web.Controllers;
using Castle.MicroKernel.Registration;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using System.Collections.Generic;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.AspNetCore.Authentication.Cookies;
using Abp.Reflection.Extensions;
namespace *****.CentralPortal.Web.Tests
{
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkInMemoryDatabase();
services.AddMvc()
.PartManager.ApplicationParts.Add(new AssemblyPart(typeof(Web.Startup.CentralPortalWebModule).GetAssembly()));
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie("Cookies")
.AddOpenIdConnect(options => SetOpenIdConnectOptions(options));
services = SetAuthorizations(services);
//Configure Abp and Dependency Injection
return services.AddAbp<CentralPortalWebTestModule>(options =>
{
options.SetupTest();
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
UseInMemoryDb(app.ApplicationServices);
app.UseAbp(); //Initializes ABP framework.
app.UseExceptionHandler("/Error");
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
app.UseAuthentication();
}
private void UseInMemoryDb(IServiceProvider serviceProvider)
{
var builder = new DbContextOptionsBuilder<CentralPortalDbContext>();
builder.UseInMemoryDatabase(Guid.NewGuid().ToString()).UseInternalServiceProvider(serviceProvider);
var options = builder.Options;
var iocManager = serviceProvider.GetRequiredService<IIocManager>();
iocManager.IocContainer
.Register(
Component.For<DbContextOptions<CentralPortalDbContext>>()
.Instance(options)
.LifestyleSingleton()
);
}
private void SetOpenIdConnectOptions(OpenIdConnectOptions options)
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:50052";
options.RequireHttpsMetadata = false;
options.ClientId = "centralportal";
options.ClientSecret = "*************";
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.MetadataAddress = $"http://localhost:50052/.well-known/openid-configuration";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("auditingApi");
options.Scope.Add("ordersApi");
options.Scope.Add("identityApi");
options.Scope.Add("offline_access");
options.Scope.Add("role");
}
//Helper method to add all authorization policies
//Keeps the ConfigureServices method cleaner.
private IServiceCollection SetAuthorizations(IServiceCollection services)
{
services.AddAuthorization(options =>
options
.AddPolicy("TestResults", builder =>
{
builder.RequireClaim("role", new List<string> { "TestResults" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("Orders", builder =>
{
builder.RequireRole(new[] { "Orders" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("HomePage", builder =>
{
builder.RequireRole(new[] { "HomePage" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("Dashboard", builder =>
{
builder.RequireRole(new[] { "Dashboard" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("UserAdmin", builder =>
{
builder.RequireRole(new[] { "UserAdmin" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("CustomerAdmin", builder =>
{
builder.RequireRole(new[] { "CustomerAdmin" });
})
);
return services;
}
}
}
WebTestBase:
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Abp.AspNetCore.TestBase;
using *****.CentralPortal.EntityFrameworkCore;
using *****.CentralPortal.Tests.TestDatas;
using AngleSharp.Dom.Html;
using AngleSharp.Parser.Html;
using Microsoft.AspNetCore.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Shouldly;
using Abp.Dependency;
namespace *****.CentralPortal.Web.Tests
{
public abstract class CentralPortalWebTestBase : AbpAspNetCoreIntegratedTestBase<Startup>
{
protected static readonly Lazy<string> ContentRootFolder;
//IIocManager _IocManager;
static CentralPortalWebTestBase()
{
ContentRootFolder = new Lazy<string>(WebContentDirectoryFinder.CalculateContentRootFolder, true);
}
protected CentralPortalWebTestBase() : base()
{
UsingDbContext(context => new TestDataBuilder(context).Build());
}
protected override IWebHostBuilder CreateWebHostBuilder()
{
var _ContentRootFolder = new Lazy<string>(WebContentDirectoryFinder.CalculateContentRootFolder, true);
UsingDbContext(context => new TestDataBuilder(context).Build());
return base
.CreateWebHostBuilder()
.UseStartup<Startup>()
.UseContentRoot(_ContentRootFolder.Value);
}
#region Get response
protected async Task<T> GetResponseAsObjectAsync<T>(string url,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK)
{
var strResponse = await GetResponseAsStringAsync(url, expectedStatusCode);
return JsonConvert.DeserializeObject<T>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
protected async Task<string> GetResponseAsStringAsync(string url,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK)
{
var response = await GetResponseAsync(url, expectedStatusCode);
return await response.Content.ReadAsStringAsync();
}
protected async Task<HttpResponseMessage> GetResponseAsync(string url,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK)
{
var response = await Client.GetAsync(url);
response.StatusCode.ShouldBe(expectedStatusCode);
return response;
}
#endregion
#region UsingDbContext
protected void UsingDbContext(Action<CentralPortalDbContext> action)
{
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
action(context);
context.SaveChanges();
}
}
protected T UsingDbContext<T>(Func<CentralPortalDbContext, T> func)
{
T result;
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
result = func(context);
context.SaveChanges();
}
return result;
}
protected async Task UsingDbContextAsync(Func<CentralPortalDbContext, Task> action)
{
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
await action(context);
await context.SaveChangesAsync(true);
}
}
protected async Task<T> UsingDbContextAsync<T>(Func<CentralPortalDbContext, Task<T>> func)
{
T result;
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
result = await func(context);
context.SaveChanges();
}
return result;
}
#endregion
#region ParseHtml
protected IHtmlDocument ParseHtml(string htmlString)
{
return new HtmlParser().Parse(htmlString);
}
#endregion
}
}
Web测试模块
using Abp.AspNetCore.TestBase;
using Abp.Modules;
using Abp.Reflection.Extensions;
using Castle.MicroKernel.Registration;
using Castle.Windsor.MsDependencyInjection;
using *****.CentralPortal.EntityFrameworkCore;
using *****.CentralPortal.Web.Startup;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace *****.CentralPortal.Web.Tests
{
[DependsOn(
typeof(CentralPortalWebModule),
typeof(CentralPortalEntityFrameworkCoreModule),
typeof(AbpAspNetCoreTestBaseModule)
)]
public class CentralPortalWebTestModule : AbpModule
{
public override void PreInitialize()
{
Configuration.UnitOfWork.IsTransactional = false; //EF Core InMemory DB does not support transactions.
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(CentralPortalWebTestModule).GetAssembly());
SetupInMemoryDb();
}
private void SetupInMemoryDb()
{
var services = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase();
var serviceProvider = WindsorRegistrationHelper.CreateServiceProvider(
IocManager.IocContainer,
services
);
var builder = new DbContextOptionsBuilder<CentralPortalDbContext>();
builder.UseInMemoryDatabase().UseInternalServiceProvider(serviceProvider);
IocManager.IocContainer.Register(
Component
.For<DbContextOptions<CentralPortalDbContext>>()
.Instance(builder.Options)
.LifestyleSingleton()
);
}
}
}
网络测试课程:
using System.Threading.Tasks;
using *****.CentralPortal.Web.Controllers;
using Shouldly;
using Xunit;
namespace *****.CentralPortal.Web.Tests.Controllers
{
public class HomeController_Tests: CentralPortalWebTestBase
{
[Fact]
public async Task Index_Test()
{
string url = GetUrl<HomeController>(nameof(HomeController.Index));
//Act
var response = await GetResponseAsStringAsync(
url
);
//Assert
response.ShouldNotBeNullOrEmpty();
}
[Fact]
public async void ShouldOnlyShowHomeMenuWhenNotAuthorized()
{
var response = await GetResponseAsStringAsync(
GetUrl<HomeController>(nameof(HomeController.Index))
);
//Parse the response for menuitems, count them and assert
int menuitemcount = 0;
string statuscode = "";//TODO: Gotta parse the response string to get the code
Assert.Equal(menuitemcount, 2);
}
}
}
我不确定为什么此时IocManager为null。我猜这是我所缺少的简单配置项,但是我似乎找不到它或任何与我现有配置不同的示例。
任何帮助将不胜感激。
根据要求:完全例外。
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] System.NullReferenceException : Object reference not set to an instance of an object.
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] Stack Trace:
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] C:\ProjectCode\*****\*****_CentralPortal\test\*****.CentralPortal.Web.Tests\CentralPortalWebTestBase.cs(78,0): at *****.CentralPortal.Web.Tests.CentralPortalWebTestBase.UsingDbContext(Action`1 action)
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] C:\ProjectCode\*****\*****_CentralPortal\test\*****.CentralPortal.Web.Tests\CentralPortalWebTestBase.cs(37,0): at *****.CentralPortal.Web.Tests.CentralPortalWebTestBase.CreateWebHostBuilder()
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] D:\Github\aspnetboilerplate\src\Abp.AspNetCore.TestBase\AbpAspNetCoreIntegratedTestBase.cs(30,0): at Abp.AspNetCore.TestBase.AbpAspNetCoreIntegratedTestBase`1..ctor()
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] C:\ProjectCode\*****\*****_CentralPortal\test\*****.CentralPortal.Web.Tests\CentralPortalWebTestBase.cs(28,0): at *****.CentralPortal.Web.Tests.CentralPortalWebTestBase..ctor()
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] at *****.CentralPortal.Web.Tests.Controllers.HomeController_Tests..ctor()
答案 0 :(得分:0)
因此,这是Web测试模块中的以下内容。我不确定我从哪里得到的,我认为这是我从中得到的例子。注释掉SetupInMemoryDb();解决了这个问题。
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(CentralPortalWebTestModule).GetAssembly());
SetupInMemoryDb();
}
private void SetupInMemoryDb()
{
var services = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase();
var serviceProvider = WindsorRegistrationHelper.CreateServiceProvider(
IocManager.IocContainer,
services
);
var builder = new DbContextOptionsBuilder<CentralPortalDbContext>();
builder.UseInMemoryDatabase().UseInternalServiceProvider(serviceProvider);
IocManager.IocContainer.Register(
Component
.For<DbContextOptions<CentralPortalDbContext>>()
.Instance(builder.Options)
.LifestyleSingleton()
);
}