【问题标题】:Unit Test IdentityDbContext单元测试 IdentityDbContext
【发布时间】:2015-06-27 14:30:23
【问题描述】:

我读到新的 EF7 允许在内存中存储,这使得单元测试更容易。这在 DbContext 上效果很好,但到目前为止我遇到的问题是我使用的是 IdentityDbContext,它没有附带该选项,或者我到目前为止还没有找到它。

我要做的是向我的 AccountController 添加单元测试,这取决于新的 UserManager 和 SignInManager 类。我想针对内存列表进行测试,但我仍然不知道如何使这些类使用不同于 EF-SQL IdentityDbContext 的 dbcontext。有没有办法解决这个问题?

【问题讨论】:

  • 您可以使用 Effort 测试内存中的 DbContext(如 my blog 中所述)。但是需要注意的一点是,IdentityDbContext 采用 DbContext 没有的第三个参数,因此您可能需要了解如何使用它。这完全不包括 EF7 提供的内存存储。
  • @JeroenVannevel 感谢您的回复,我尝试按照您的建议使用 Effort,问题是 IdentityDbContext 的当前实现只包含一个无参数构造函数 link 所以我无法传递我从 Effort 获得的连接字符串

标签: asp.net entity-framework unit-testing asp.net-identity asp.net-core


【解决方案1】:

十二月。 2015 年 27 月 - RC1 更新

项目.json

{
  "version": "1.0.0-*",
  "dependencies": {
    "{assembly under test}": "",
    "Microsoft.AspNet.Hosting": "1.0.0-*",
    "xunit": "2.1.0",
    "xunit.runner.dnx": "2.1.0-rc1-*"
  },
  "commands": {
    "test": "xunit.runner.dnx"
  },
  "frameworks": {
    "dnx451": {
      "dependencies": {
        "Moq": "4.2.1312.1622"
      }
    }
  }
}

一个测试 AccountController 的测试类示例:

using {Your NS}.Controllers;
using Microsoft.AspNet.Identity;
using Moq;
using Xunit;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.Extensions.OptionsModel;
using System.Threading;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.Extensions.Logging;

namespace NS.test.Controllers
{
    public class TestRole
    {
        public string Id { get; private set; }
        public string Name { get; set; }
    }

    public interface ITestUserStore<T>:IUserStore<T>, IUserPasswordStore<T> where T :class
    { }

    public class AccountControllerTest
    {
        private static UserManager<TUser> GetUserManager<TUser>(List<IUserValidator<TUser>> userValidators) where TUser : class
        {
            var store = new Mock<ITestUserStore<TUser>>();
            store.Setup(s => s.CreateAsync(It.IsAny<TUser>(), It.IsAny<CancellationToken>())).ReturnsAsync(IdentityResult.Success);
            var options = new Mock<IOptions<IdentityOptions>>();
            var idOptions = new IdentityOptions();
            idOptions.Lockout.AllowedForNewUsers = false;
            options.Setup(o => o.Value).Returns(idOptions);
            var pwdValidators = new List<PasswordValidator<TUser>>();
            pwdValidators.Add(new PasswordValidator<TUser>());
            var userManager = new UserManager<TUser>(store.Object, options.Object, new PasswordHasher<TUser>(),
                userValidators, pwdValidators, new UpperInvariantLookupNormalizer(),
                new IdentityErrorDescriber(), null,
                new Mock<ILogger<UserManager<TUser>>>().Object,
                null);

            return userManager;
        }

        private static Mock<SignInManager<TUser>> MockSigninManager<TUser>(UserManager<TUser> userManager) where TUser : class
        {            
            var context = new Mock<HttpContext>();
            var contextAccessor = new Mock<IHttpContextAccessor>();
            contextAccessor.Setup(a => a.HttpContext).Returns(context.Object);

            var roleManager = new RoleManager<TestRole>(new Mock<IRoleStore<TestRole>>().Object,new RoleValidator<TestRole>[] { new RoleValidator<TestRole>() }, null, null, null, null);
            var identityOptions = new IdentityOptions();
            var options = new Mock<IOptions<IdentityOptions>>();
            options.Setup(a => a.Value).Returns(identityOptions);
            var claimsFactory = new UserClaimsPrincipalFactory<TUser, TestRole>(userManager, roleManager, options.Object);
            return new Mock<SignInManager<TUser>>(userManager, contextAccessor.Object, claimsFactory, options.Object, null);
        }


        [Fact]
        public async Task RegisterTest()
        {
            var userValidators = new List<IUserValidator<YourUser>>();
            var validator = new Mock<IUserValidator<YourUser>>();
            userValidators.Add(validator.Object);
            var userManager = GetUserManager(userValidators);

            validator.Setup(v => v.ValidateAsync(userManager, It.IsAny<ChatLeUser>()))
               .Returns(Task.FromResult(IdentityResult.Success)).Verifiable();

            var signinManager = MockSigninManager<YourUser>(userManager);
            signinManager.Setup(m => m.SignInAsync(It.IsAny<YourUser>(), It.IsAny<bool>(), null)).Returns(Task.FromResult(0)).Verifiable();
            var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary());
            using (var controller = new AccountController(userManager, signinManager.Object) { ViewData = viewData })
            {
                var result = await controller.Register(new RegisterViewModel()
                {
                    ConfirmPassword = "test123",
                    Password = "Test123-123",
                    UserName = "test"
                });

                Assert.IsType<RedirectToActionResult>(result);
            }
        }
    }
}

【讨论】:

  • 谢谢!这正是我所需要的。需要注意的一件事,不再支持 xunit.runner.kre,我将其更改为 xunit.runner.aspnet,一切顺利
  • 我在调试模式下使用 aspnet runner 时遇到了多线程问题!
  • 我忘了说你还需要给xunit添加一个依赖(抱歉),更多信息here
  • 我会通过修复构建版本重试,也许有帮助
  • 这在 VS 中完全不起作用,我尝试使用 "xunit": "2.1.0-beta1-*", "xunit.runner.aspnet": "2.1.0-beta1-*",但 VS 没有发现测试。我试过 "xunit": "2.1.0-beta1-*", "xunit.runner.aspnet": "2.1.0-beta1-*" ; VS 卡住了
【解决方案2】:

最终,您可能希望直接模拟 UserManagerSignInManager。不幸的是,beta-3 下的许多方法都不是虚拟的。你会有点卡在那里。但是,您可以从 UserManagerSignInManager 的来源中看到,身份团队似乎正在为下一个版本解决这些问题。

由于同样的问题,我个人有几个测试没有编译。

【讨论】:

    猜你喜欢
    • 2014-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2011-04-12
    相关资源
    最近更新 更多