如何使用NUnit在.NET Core中模拟UserManager?

时间:2018-06-16 15:52:45

标签: c# unit-testing asp.net-core asp.net-core-identity

我想用Razor Pages对使用.NET Core制作的应用程序进行单元测试。我需要模仿我的dbContext和我的UserManager - 然而,我似乎不断回复null

FakeUserManager

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)
    { }
}

我的TestClass

 [TestFixture]
 public class UserTest
 {
     private ApplicationDbContext _dbContext { get; set; }
     public void TestSetUp()
     {
         DbContextOptionsBuilder<ApplicationDbContext> optionsbuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
         optionsbuilder.UseInMemoryDatabase(databaseName: "TestDB");
         _dbContext = new ApplicationDbContext(optionsbuilder.Options);
         _dbContext.Users.Add(new ApplicationUser
         {
             Id = "1",
             FirstName = "Test",
             LastName = "Alpha",
             CreatedAt = DateTime.Now,
             UpdatedAt = DateTime.Now,
         });
         _dbContext.SaveChanges();
     }

     [Test]
     public void MyTest()
     {
         Mock<FakeUserManager> fakeUserManager = new Mock<FakeUserManager>();
         var result = fakeUserManager.Object.FindByIdAsync("1");

         // I know this Assert always returns  success, but I'd like var result to return my ApplicationUser found by the FakeUserManager
         Assert.AreEqual("test", "test");
     }
 }

在将此问题标记为重复之前,是的 - 我会查看其他帖子,但他们不满足我的答案。

当我运行此测试时,var result会返回null,我不明白为什么。

编辑###

    [Test]
    public async void MyTest() 
    {
        var mockStore = Mock.Of<IUserStore<ApplicationUser>>();
        var mockUserManager = new Mock<UserManager<ApplicationUser>>(mockStore, null, null, null, null, null, null, null, null);

        var user = new ApplicationUser
        {
            Id = "1",
            FirstName = "Test",
            LastName = "Test"
        };

        mockUserManager
            .Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>()))
            .ReturnsAsync(IdentityResult.Success);

        await mockUserManager.Object.CreateAsync(user);

        var result = mockUserManager.Object.FindByIdAsync("UserA");

        Assert.AreEqual("test", "test");


    }

1 个答案:

答案 0 :(得分:3)

您不应测试UserManager是否可以从数据库中检索数据(这是超出您范围的框架的内部问题)。相反,您应该像这样模拟UserManager的FindByIdAsync功能:

var UserStoreMock = Mock.Of<IUserStore<AppUser>>();
var userMgr = new Mock<UserManager<AppUser>>(UserStoreMock, null, null, null, null, null, null, null, null);
var user = new AppUser() { Id = "f00", UserName = "f00", Email = "f00@example.com" };
var tcs = new TaskCompletionSource<AppUser>();
tcs.SetResult(user);
userMgr.Setup(x => x.FindByIdAsync("f00")).Returns(tcs.Task);

对于您的身份设置,以确保具有适当权限的经过身份验证的用户正在拨打电话:

Mock<ClaimsPrincipal> ClaimsPrincipalMock = new Mock<ClaimsPrincipal>();
ClaimsPrincipalMock.Setup(x => x.IsInRole("Admin")).Returns(true);
ClaimsPrincipalMock.Name = "SomeAdmin";
ClaimsPrincipalMock.SetupGet(x => x.Identity.Name).Returns(ClaimsPrincipalMock.Name);

然后为您的帐户控制器设置上下文,如下所示,将UserManager传递为DI参数之一:

AccountController SUT = new AccountController(userMgr);
var context = new ControllerContext();
context.HttpContext = new DefaultHttpContext();
context.HttpContext.User = ClaimsPrincipalMock.Object;
SUT.ControllerContext = context;

最后,在您的控制器中,匹配的代码如下:

[HttpGet("User")]
public async Task<IActionResult> GetUser(string id)
{
    var user = await _userManager.FindByIdAsync(id);     
    bool isAdmin= User.IsInRole("Admin");

    if (user == default(AppUser) || (User.Identity.Name != user.UserName && isAdmin == false))
    {
         return NotFound();
    }

    return Ok(user);
}