简体   繁体   English

具有授权ASP.NET Core 2.0 Web API的单元测试控制器

[英]Unit Testing Controller with Authorization ASP.NET Core 2.0 Web API

I have a controller: 我有一个控制器:

public class InvitationsController: Controller {
        private readonly IMapper _mapper;
        private readonly IInvitationManager _invitationManager;
        private readonly UserManager<MyAppUser> _userManager;

        public InvitationsController(
            IInvitationManager invitationManager,
            IMapper mapper,
            UserManager<MyAppUser> userManager,
            IJobManager jobManager
        ) {
            _invitationManager = invitationManager;
            _mapper = mapper;
            _userManager = userManager;
        } 
[Authorization]
GetInvitationByCode(string code) { ... }

I'm trying to write unit tests using Xunit and Moq. 我正在尝试使用Xunit和Moq编写单元测试。 Here is the implentation of my test: 这是我的测试的实现:

  public class InvitationsControllerTests {

    private Mock<IInvitationManager> invitationManagerMock;        
    private Mock<UserManager<MyAppUser>> userManagerMock;
    private Mock<IMapper> mapperMock;
    private InvitationsController controller;

    public InvitationsControllerTests() {
        invitationManagerMock = new Mock<IInvitationManager>();          
        userManagerMock = new Mock<UserManager<MyAppUser>>();

        mapperMock = new Mock<IMapper>();
        controller = new InvitationsController(invitationManagerMock.Object,
                   mapperMock.Object,
                   userManagerMock.Object);
    }

    [Fact]
    public async Task GetInvitationByCode_ReturnsInvitation() {

        var mockInvitation = new Invitation {
            StoreId = 1,
            InviteCode = "123abc",
        };

        invitationManagerMock.Setup(repo => 
        repo.GetInvitationByCodeAsync("123abc"))
            .Returns(Task.FromResult(mockInvitation));

        var result = await controller.GetInvitationByCode("123abc");

        Assert.Equal(mockInvitation, result);
    }

I don't think I'm using the mocking functionality correctly. 我认为我没有正确使用模拟功能。 Specifically with UserManager. 特别是使用UserManager。 I can't find a clear answer on using Moq to test controllers protected by [Authorize]. 我无法找到使用Moq测试受[Authorize]保护的控制器的明确答案。 When running my tests, it throws an exception on 运行我的测试时,它会抛出异常

        controller = new InvitationsController(invitationManagerMock.Object,
                   mapperMock.Object,
                   userManagerMock.Object);

Which reads: 其中包括:

Castle.DynamicProxy.InvalidProxyConstructorArgumentsException: 'Can not instantiate proxy of class: Microsoft.AspNetCore.Identity.UserManager`1[[MyApp.api.Core.Models.MyAppUser, MyApp.api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Castle.DynamicProxy.InvalidProxyConstructorArgumentsException:'无法实例化类的代理:Microsoft.AspNetCore.Identity.UserManager`1 [[MyApp.api.Core.Models.MyAppUser,MyApp.api,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = NULL]]。 Could not find a parameterless constructor.' 找不到无参数构造函数。'

You're not unit testing; 你不是单元测试; you're integration testing. 你是集成测试。 When you find yourself setting up ten thousand mocks just to run a method, that's a pretty good sign it's an integration test. 当你发现自己设置了一万个模拟只是为了运行一个方法时,这是一个非常好的迹象,它是一个集成测试。 Additionally, things like authorization only happen as part of the request lifecycle; 此外,授权等事项仅作为请求生命周期的一部分发生; there's no way to test that, without doing an actual request, which again, means you're integration testing. 在没有做出实际请求的情况下,没有办法测试它,这再次意味着你进行了集成测试。

As such, use the test host . 因此,请使用测试主机

private readonly TestServer _server;
private readonly HttpClient _client;

public MyTestClass()
{
    _server = new TestServer(new WebHostBuilder()
        .UseStartup<Startup>());
    _client = _server.CreateClient();
}

[Fact]
public async Task GetInvitationByCode_ReturnsInvitation() {

    var mockInvitation = new Invitation {
        StoreId = 1,
        InviteCode = "123abc",
    };

    var response = await _client.GetAsync("/route");
    response.EnsureSuccessStatusCode();

    var responseString = await response.Content.ReadAsStringAsync();
    var result = JsonConvert.DeserializeObject<Invitation>(responseString);

    // Compare individual properties you care about.
    // Comparing the full objects will fail because of reference inequality
    Assert.Equal(mockInvitation.StoreId, result.StoreId);
}

If you need to scaffold your data to make the correct result return, simply use the in-memory database provider . 如果您需要为数据构建工具以返回正确的结果,只需使用内存数据库提供程序即可 The easiest way to use this for integration testing is to specify a new environment like "Test". 使用它进行集成测试的最简单方法是指定一个像“Test”这样的新环境。 Then, in your startup, when configuring your context, branch on the environment and use the in-memory provider (instead of SQL Server or whatever) when the environment is "Test". 然后,在启动时,在配置上下文时,分支环境并在环境为“Test”时使用内存提供程序(而不是SQL Server或其他)。 Then, when setting up your test server for integration testing, simply add .UseEnvironment("Test") before .UseStartup<Startup>() . 然后,在设置测试服务器进行集成测试时,只需在.UseStartup<Startup>()之前添加.UseEnvironment("Test") .UseStartup<Startup>()

I think, problem is in dependency injection. 我认为,问题在于依赖注入。 In your Startups.cs file you could find similar string: services.AddIdentity<AppUser, AppRole>().AddEntityFrameworkStores<AppDbContext>().AddDefaultTokenProviders(); 在您的Startups.cs文件中,您可以找到类似的字符串: services.AddIdentity<AppUser, AppRole>().AddEntityFrameworkStores<AppDbContext>().AddDefaultTokenProviders(); it means that magic of namespace Microsoft.Extensions.DependencyInjection provide you an instance of your User- or RoleManger anywhere where you want to use it. 它意味着名称空间Microsoft.Extensions.DependencyInjection魔力为您提供了一个用户或RoleManger实例,您可以在任何地方使用它。 For example, in InvitationsController using injectin in constructor. 例如,在构造函数中使用injectin的InvitationsController中。

You can try inject UserManger in test class and mock it. 您可以尝试在测试类中注入UserManger并进行模拟。 Or read similar question 或者阅读类似的问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在ASP.NET Core MVC API控制器上单元测试AuthorizeAttribute - Unit testing an AuthorizeAttribute on an ASP.NET Core MVC API controller 单元测试 - 控制器没有从ASP.NET Core Web API项目中的模拟IConfiguration中获取值 - Unit Testing - Controller not picking up value from mocked IConfiguration in ASP.NET Core Web API Project 我应该向控制器传递什么才能在 ASP.NET Core 2.0 中执行模型单元测试 - What should I pass to controller in order to perform model unit testing in ASP.NET Core 2.0 单元测试ASP.NET Web API - Unit Testing ASP.NET Web API ASP.NET Core 2.0 Web API Azure Ad v2令牌授权无效 - ASP.NET Core 2.0 Web API Azure Ad v2 Token Authorization not working 控制器中Asp.Net核心单元测试删除方法 - Asp.Net Core Unit Testing Delete Method in controller 单元测试依赖于User.Identity对象的ASP.Net Web API控制器 - Unit Testing an ASP.Net Web API Controller that relies on the User.Identity object ASP.NET Web API单元测试-从返回JsonResult的控制器读取Json字符串 - ASP.NET Web API Unit Testing - Read Json string from controller returning JsonResult 单元测试返回自定义结果的ASP.NET Web API 2 Controller - Unit testing ASP.NET Web API 2 Controller which returns custom result 处理身份验证/授权:ASP.NET Core Web 应用程序 =&gt; ASP.NET Core Web API =&gt; SQL - Handling authentication/authorization: ASP.NET Core Web Application => ASP.NET Core Web API => SQL
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM