我正在为下面的控制器编写Xunit测试。当我运行我的测试时,我收到此错误
object reference is notset to an instance of an object
这是我的测试代码
[Fact]
public async Task RegistrationTest()
{
ctrl = new AccountsControllers(context, userManager, jwtFactory, jwtoptions);
ctrl.ModelState.AddModelError("x", "Model error");
var mod = new RegistrationViewModel
{
Email = "johnmiller@sins.com"
};
IActionResult result = await ctrl.Register(mod);
// Assert.Equal(mod.Email, moe);
var viewresult = Assert.IsType<BadRequestObjectResult>(result);
}
但是,我成功为context,usermanager
创建了实例var services = new ServiceCollection();
services.AddDbContext<ApplicationContext>(options => options
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Inventory;Trusted_Connection=True;ConnectRetryCount=0"));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationContext>();
var con = new DefaultHttpContext();
con.Features.Set<IHttpAuthenticationFeature>(new HttpAuthenticationFeature());
services.AddSingleton<IHttpContextAccessor>(h => new HttpContextAccessor { HttpContext = con });
var serviceProvider = services.BuildServiceProvider();
context = serviceProvider.GetRequiredService<ApplicationContext>();
userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
我没有得到如何为IJwtFactory和JwtIssuerOptions创建
这是我的帐户控制器构造函数
public AccountsControllers(ApplicationContext context, UserManager<ApplicationUser> userManager,
IJwtFactory jwtFactory, IOptions<JwtIssuerOptions> jwtoptions)
{
appDbContext = context;
this.userManager = userManager;
this.jwtFactory = jwtFactory;
jwtOptions = jwtoptions.Value;
serializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented
};
}
这是帐户控制器中的Loginmethod
public async Task<IActionResult> Login([FromBody]LoginViewModel credentials)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var identity = await GetClaimsIdentity(credentials.UserName, credentials.Password);
if (identity == null)
{
return BadRequest(Errors.AddErrorToModelState("login_failure", "Invalid username or password.", ModelState));
}
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await jwtFactory.GenerateEncodedToken(credentials.UserName, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
};
var json = JsonConvert.SerializeObject(response, serializerSettings);
return new OkObjectResult(json);
}
ClaimsIdentity
public async Task<ClaimsIdentity> GetClaimsIdentity(string userName, string password)
{
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
{
// get the user to verifty
var userToVerify = await userManager.FindByNameAsync(userName);
if (userToVerify != null)
{
// check the credentials
if (await userManager.CheckPasswordAsync(userToVerify, password))
{
return await Task.FromResult(jwtFactory.GenerateClaimsIdentity(userName, userToVerify.Id));
}
}
}
return await Task.FromResult<ClaimsIdentity>(null);
}
答案 0 :(得分:0)
问题在于你试图嘲笑你所有的依赖项,而你显然在某处遗漏了某些东西。每当你发现自己需要模拟多个依赖项时,这就是你在集成测试领域的一个非常明显的标志。
通常,只要您测试控制器操作,就会进行集成测试。虽然它们看起来像类上的方法一样,但是需要在请求管道的一部分中实现它们才能使它们正常运行,如果没有实际请求就无法真正测试它们。特别是,使用经过身份验证的用户创建HttpContext
之类的事情不会发生在请求管道之外。你也可以在技术上模拟所有这些,但同样,这只是你需要手动提供的更多依赖项,以及更多创建测试失败的机会因为设置不正确而不是因为任何事实上错误< / em>的
既然如此,实际上是进行真正的集成测试并使用TestServer
。您可以将它Startup
类提供给它,以便所有服务都按照应有的方式注册和注入,然后您只需发出请求并验证响应对象。对于像数据库连接这样的模拟,你应该设置一个“测试”环境并在Startup.cs中配置它以使用内存中的EF数据库提供程序。然后,您可以指定您的TestServer
应该使用该“测试”环境,并且您很高兴。有关详细信息,请参阅documentation。