如何通过模拟IUserService对我的reportcontroller进行单元测试

时间:2018-02-14 21:15:04

标签: asp.net-mvc unit-testing asp.net-core moq

我有一个控制器:

private readonly IUserService _userService;

    public ReportController ( IOptions<AppSettings> appSettings,
                              UserManager<ApplicationUser> userManager,
                              IUserService userService ) : base( appSettings, userManager ) {
        _userService = userService;
    }

    public async Task<ActionResult> Report ( string path ) {
        var currentUser = await GetCurrentUserAsync();
        var excludedItems = _userService.GetUserExcludedReportsById( currentUser.Id ).Select( er => er.Path );

        if ( string.IsNullOrEmpty( path ) || excludedItems.Any( path.Contains ) ) {
            return RedirectToAction( nameof(HomeController.Index), "Home" );
        }

        var customItems = _userService.GetUserCustomReportsById( currentUser.Id ).Select( er => er.Path );

        if ( path.Contains( AppSettings.CustomReportsFolderName ) && !customItems.Any( path.Contains ) ) {
            return RedirectToAction( nameof(HomeController.Index), "Home" );
        }


        var model = GetReportViewerModel( Request );
        model.Parameters.Clear();
        var dbname = _userService.GetDefaultDbName( (await GetCurrentUserAsync()).Id );
        model.Parameters.Add( "connectionStr", new[] {
            dbname
        } );
        model.ReportPath = path;
        model.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Ntlm;

        return View( "Report", model );
    }
}

你能告诉我如何进行单元测试吗?我的主要问题是:

它在构造函数中有3个依赖项,我已经设法将它们与UserManager需求区分开来,而UserManager需求本身似乎有很多依赖项。我已尝试过该网站的建议,如下所示,但UserManager对象抱怨缺少参数。我一直被告知它应该很简单,但我确实需要这些实例化控制器的实例吗?

关于在Report方法上测试的内容,我的想法是:两个IF语句返回重定向。预期回报也是有效的。

到目前为止,我有:

var mockUserService = new Mock<IUserService>();
        AppSettings appSettings = new AppSettings() { };
        IOptions<AppSettings> options = Options.Create(appSettings);
        var mockUserStore = new Mock<IUserStore<ApplicationUser>>(MockBehavior.Strict);
        var userManager = new UserManager<ApplicationUser>(mockUserStore.Object);
        var mockDependancyResolver = new Mock<IDependencyResolver>();

        var sut = new ReportController(options, userManager.Object, mockUserService.Object);

1 个答案:

答案 0 :(得分:0)

  

我一直被告知它应该很简单

通常,当您的控制器仅依赖于抽象(即接口)时,它很简单。然后你可以使用Mock类来模拟它们。但UserManager<>不是抽象,它是一个不能被Mock嘲笑的具体类。但由于UserManager<>的大多数方法都是虚拟的,因此您可以从中获取并覆盖它们:

public class FakeUserManager : UserManager<ApplicationUser>
{
    public FakeUserManager()
        : base(new Mock<IUserStore<ApplicationUser>>().Object,
              new Mock<IOptions<IdentityOptions>>().Object,
              new Mock<IPasswordHasher<ApplicationUser>>().Object,
              new IUserValidator<ApplicationUser>[0],
              new IPasswordValidator<ApplicationUser>[0],
              new Mock<ILookupNormalizer>().Object,
              new Mock<IdentityErrorDescriber>().Object,
              new Mock<IServiceProvider>().Object,
              new Mock<ILogger<UserManager<ApplicationUser>>>().Object)
    { }
    ...
    public override Task<ApplicationUser> FindByIdAsync(string id)
    {
        return Task.FromResult(new ApplicationUser { Id = id });
    }
    ...
}

然后使用它:

var sut = new ReportController(options, new FakeUserManager(), mockUserService.Object);