Asp.net core mvc 如何将对象引用设置为对象的实例

Asp.net core mvc 如何将对象引用设置为对象的实例,asp.net-core-mvc,jwt,claims-based-identity,xunit,xunit.net,Asp.net Core Mvc,Jwt,Claims Based Identity,Xunit,Xunit.net,我正在为下面的控制器编写Xunit测试。当我运行我的测试时,我得到了这个错误 object reference is notset to an instance of an object 这是我的测试代码 [Fact] public async Task RegistrationTest() { ctrl = new AccountsControllers(context, userManager, jwtFactory, jwtoptions); ctrl

我正在为下面的控制器编写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);

    }
[事实]
公共异步任务注册测试()
{
ctrl=新的AccountsController(上下文、用户管理器、jwtFactory、jwtoptions);
ctrl.ModelState.AddModelError(“x”,“模型错误”);
var mod=新注册视图模型
{
电子邮件=”johnmiller@sins.com"
};
IActionResult结果=等待控制寄存器(mod);
//断言相等(mod.Email,moe);
var viewresult=Assert.IsType(结果);
}
但是,我成功地为上下文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>>();
var services=newservicecolection();
AddDbContext(选项=>options
.UseSqlServer(@“服务器=(localdb)\mssqllocaldb;数据库=库存;可信连接=True;ConnectRetryCount=0”);
服务.额外性()
.AddEntityFrameworkStores();
var con=新的DefaultHttpContext();
con.Features.Set(新的HttpAuthenticationFeature());
AddSingleton(h=>newHttpContextAccessor{HttpContext=con});
var serviceProvider=services.BuildServiceProvider();
context=serviceProvider.GetRequiredService();
userManager=serviceProvider.GetRequiredService();
我不知道如何创建IJwtFactory和jwtissueoptions

这是我的帐户控制器构造函数

 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
        };
    }
公共帐户控制器(ApplicationContext上下文、UserManager、UserManager、, IJwtFactory jwtFactory,IOptions jwtoptions) { appDbContext=context; this.userManager=userManager; this.jwtFactory=jwtFactory; jwtOptions=jwtOptions.Value; serializerSettings=新JsonSerializerSettings { 格式化=格式化。缩进 }; } 这是accounts controller中的登录方法

 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);
    }
公共异步任务登录([FromBody]LoginViewModel凭据)
{
如果(!ModelState.IsValid)
{
返回请求(ModelState);
}
var identity=await GetClaimsIdentity(credentials.UserName,credentials.Password);
if(identity==null)
{
返回BadRequest(Errors.AddErrorToModelState(“登录失败”,“用户名或密码无效”,ModelState));
}
var响应=新
{
id=identity.Claims.Single(c=>c.Type==“id”).Value,
auth_token=wait jwtFactory.GenerateEncodedToken(credentials.UserName,identity),
expires_in=(int)jwtOptions.ValidFor.TotalSeconds
};
var json=JsonConvert.SerializeObject(响应,serializerSettings);
返回新的OkObjectResult(json);
}
索赔性

    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);
    }
public异步任务GetClaimsIdentity(字符串用户名、字符串密码)
{
如果(!string.IsNullOrEmpty(用户名)和&!string.IsNullOrEmpty(密码))
{
//让用户访问verifty
var userToVerify=await userManager.FindByNameAsync(用户名);
if(userToVerify!=null)
{
//检查凭证
if(等待userManager.CheckPasswordAsync(userToVerify,password))
{
返回wait Task.FromResult(jwtFactory.GenerateClaimsIdentity(userName,userToVerify.Id));
}
}
}
返回等待任务.FromResult(空);
}

问题在于,您试图模拟所有的依赖项,但显然在某些地方遗漏了一些东西。每当您发现自己有多个需要模拟的依赖项时,这就非常清楚地表明您正处于集成测试领域

通常,任何时候测试控制器动作都是在进行集成测试。尽管它们看起来像类上的方法,但在请求管道中有很多事情需要做,才能真正使它们正常工作,如果没有实际的请求,就无法真正测试它们。特别是,像使用经过身份验证的用户创建
HttpContext
这样的事情不会发生在请求管道之外。您也可以从技术上模拟所有这些,但同样,这只是您必须手动提供的更多依赖项,以及创建失败测试的更多机会,因为设置不正确,而不是因为任何实际错误

既然如此,那么就实际执行真正的集成测试并利用
TestServer
。您可以将
Startup
类提供给它,这样所有的服务都可以注册和注入,然后您只需发出请求并验证响应对象。对于模拟数据库连接之类的内容,您应该设置一个“测试”环境,并在Startup.cs中配置该环境,以使用内存中EF数据库提供程序之类的内容。然后,您可以指定您的
TestServer
应该使用该“测试”环境,这样就可以开始了。有关更多信息,请参阅