.net 模拟具有通用返回类型的方法

问题描述 投票:0回答:1

我正在尝试模拟一个具有在抽象类中实现的通用返回类型的方法。

抽象类代码:

public abstract class AbstractRepository<T> where T : class
{
    protected virtual async Task<T> GetById(int id)
    {
        // some code
    }
}

实现类:

public class UserRepository : AbstractRepository<User>
{
    public Task<User> GetUserById(int id)
    {
        return base.GetById(id);
    }
}

测试方法:

[Theory]
public async Task GetUserById_UserExists_ReturnsUser(User user)
{
    Mock<UserRepository> mockRealSut = new(MockBehavior.Strict, new object[] {
    })
    {
        CallBase = true
    };

    //Setup Mock
    
    //Act
    User result = await mockRealSut.Object.GetUserById(1);
}

    

我无法成功设置模拟,因为始终调用实际的抽象方法。

我尝试了两种方法:

方法一:

_ = mockRealSut.Protected().Setup<Task<User>>("GetById", ItExpr.IsAny<int>()).ReturnsAsync(user);       

方法2:

public interface IGetByIdMethodMock<T>
{
    Task<T> GetById(int id);
}

_ = mockRealSut.Protected().As<IGetByIdMethodMock<User>>().Setup(m => m.GetById(It.IsAny<int>())).ReturnsAsync(user);

stackoverflow 上的这篇文章 here 似乎表明方法 2) 应该有效,但它特定于泛型参数,而不是泛型返回类型。

我查看了 Moq 文档,但找不到解决方案。

我错过了什么吗? 我认为这应该可以通过 Moq 实现,但是缺少一些东西,我找不到问题。

这种类型的 CRUD 方法非常常见,所以如果 Moq 不涵盖这种类型的代码那就很奇怪了。

.net generics moq
1个回答
0
投票

问题是

GetUserById
方法调用了
base.GetById
:

return base.GetById(id);

这意味着它显式调用

AbstractRepository<User>.GetById
,而不是
UserRepository.GetById

当您要求 Moq 覆盖

UserRepository.GetById
时,您会这样做,但您不会覆盖
AbstractRepository<User>.GetById

GetUserById
方法更改为:

public Task<User> GetUserById(int id)
{
    return GetById(id);
}

然后这样的测试就可以了:

[Theory]
[InlineData(1)]
[InlineData(2)]
public async Task GetUserById(int id)
{
    var expected = new User();
    var repo = new Mock<UserRepository>();
    repo.Protected()
        .Setup<Task<User>>("GetById", ItExpr.Is<int>(i => i == id))
        .ReturnsAsync(expected);

    var actual = await repo.Object.GetUserById(id);

    Assert.Equal(expected, actual);
}
© www.soinside.com 2019 - 2024. All rights reserved.