【问题标题】:Asp.Net Mocking a Repository that returns a DbSet with .GetAll().ToListAsync()Asp.Net 模拟一个使用 .GetAll().ToListAsync() 返回 DbSet 的存储库
【发布时间】:2019-10-06 07:34:00
【问题描述】:

在我的 ASP.Net 应用程序中,我有一个要进行单元测试的控制器。以下是一些相关代码:

public class UserController : Controller
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly SignInManager<IdentityUser> _signInManager;
    private readonly IUserRepository _userRepository;

    public UserController(IUserRepository repo, UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
    {
        _userRepository = repo;
        _userManager = userManager;
        _signInManager = signInManager;
    }

    public async Task<IActionResult> Index()
    {
        return View(await _userRepository.GetAll().ToListAsync());
    }

我想测试 Index() 方法,所以我使用 https://github.com/romantitov/MockQueryable 创建了一个 DummyDbContext 来帮助模拟存储库。

相关代码:

public class DummyDbContext
{
    private ICollection<User> _users;
    public Mock<DbSet<User>> _dbsetUsers
    {
        get
        {
            return _users.AsQueryable().BuildMockDbSet();
        }
    }

    public DummyDbContext()
    {
        _users= new List<User>();

        _users.Add(new User("Alan"));
        _users.Add(new User("Claire"));
        _users.Add(new User("Paul"));
        _users.Add(new User("John"));
    }

在我的测试课中,我进行如下操作:

public class UserControllerTest
{
    private readonly DummyDbContext _context;
    private readonly Mock<UserManager<IdentityUser>> _userManager;
    private readonly Mock<SignInManager<IdentityUser>> _signInManager;
    private readonly Mock<IUserRepository> _userRepository;
    private readonly UserController _controller;

    public UserControllerTest()
    {
        _context = new DummyDbContext();
        _userManager = new Mock<UserManager<IdentityUser>>(
                new Mock<IUserStore<IdentityUser>>().Object,
                new Mock<IOptions<IdentityOptions>>().Object,
                new Mock<IPasswordHasher<IdentityUser>>().Object,
                new IUserValidator<IdentityUser>[0],
                new IPasswordValidator<IdentityUser>[0],
                new Mock<ILookupNormalizer>().Object,
                new Mock<IdentityErrorDescriber>().Object,
                new Mock<IServiceProvider>().Object,
                new Mock<ILogger<UserManager<IdentityUser>>>().Object);
        _signInManager = new Mock<SignInManager<IdentityUser>>(
            _userManager.Object,
            new Mock<IHttpContextAccessor>().Object,
            new Mock<IUserClaimsPrincipalFactory<IdentityUser>>().Object,
            new Mock<IOptions<IdentityOptions>>().Object,
            new Mock<ILogger<SignInManager<IdentityUser>>>().Object,
            new Mock<IAuthenticationSchemeProvider>().Object);
        _userRepository = new Mock<IUserRepository>();
        _controller = new UserController(_userRepository.Object, _userManager.Object, _signInManager.Object);
    }

    [Fact]
    public async void Index_GetModelContainingAllUsers()
    {
        _userRepository.Setup(g => g.GetAll()).Returns(_context._dbsetUsers.Object);
        var actionResult = await _controller.Index() as Task<ViewResult>;
        var usersResult = actionResult?.Result?.Model as IEnumerable<User>;
        foreach (var g in usersResult) {
            Console.WriteLine(g.Username);
        }
        Assert.Equal(4, usersResult.Count());
    }

现在,问题是 usersResult 为空。我不知道为什么;我在设置 userRepository 时做错了吗?

坦率地说,我觉得我做错了什么,不得不为应该是一个简单的模拟的东西编写所有这些代码。

【问题讨论】:

  • 您可以先在测试中直接测试您想要测试的行。然后你可以将调用分成两行并调试测试。
  • 为什么不用内存数据库?
  • @Nikolaus:我不确定你的意思,你的意思是拆分 ToAsyncList 和 GetAll 调用?
  • @H. Herzl:我该怎么做呢?坦率地说,我认为 DummyDbContext 正是如此

标签: asp.net entity-framework-core moq


【解决方案1】:

我设法解决了我自己的问题。

问题是我将 _controller.Index() 的结果转换为 Task 而我应该将其转换为 ViewResult。当任务完成(“等待”)时,我收到一个分配给 actionResult 的 ViewResult。通过将其转换为 Task 我得到了 null。

这是它应该阅读的内容:

 [Fact]
    public async void Index_GetModelContainingAllUsers()
    {
        _userRepository.Setup(g => g.GetAll()).Returns(_context._dbsetUsers.Object);
        var actionResult = await _controller.Index() as ViewResult;
        var usersResult = actionResult?.Model as IEnumerable<User>;
        Assert.Equal(4, usersResult.Count());
    }

【讨论】:

  • 有意义,因为等待任务返回 ViewResult。但是,正如您所要求的那样,用户结果并不孤单。
猜你喜欢
  • 1970-01-01
  • 2011-05-27
  • 2021-12-08
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多