You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

单元测试中如何Mock类?附完整可验证示例(跟进问题)

解决无入参有返回值方法的Mock单元测试问题

先基于你提到的控制器、OrganisationLogic和逻辑仓库的结构,还原一个典型的代码场景,再给出具体的Mock测试方案:

1. 你的代码结构示例

逻辑仓库基类

public abstract class LogicRepository
{
    // 无入参但有返回值的目标方法
    public abstract List<Organisation> GetAllOrganisations();
}

业务逻辑层

public class OrganisationLogic : LogicRepository
{
    public override List<Organisation> GetAllOrganisations()
    {
        // 实际业务逻辑:比如从数据库查询组织数据
        return new List<Organisation> { new Organisation { Id = 1, Name = "测试组织" } };
    }
}

控制器

public class OrganisationController : ControllerBase
{
    private readonly OrganisationLogic _organisationLogic;

    public OrganisationController(OrganisationLogic organisationLogic)
    {
        _organisationLogic = organisationLogic;
    }

    [HttpGet]
    public IActionResult GetAll()
    {
        var organisations = _organisationLogic.GetAllOrganisations();
        return Ok(organisations);
    }
}

2. 单元测试Mock方案(xUnit + Moq)

针对这种无入参但有返回值的方法,我们可以通过Mock抽象基类(更符合面向抽象编程的原则)来隔离业务层的实现,专注测试控制器逻辑:

using Xunit;
using Moq;

public class OrganisationControllerTests
{
    [Fact]
    public void GetAll_ReturnsOk_WithMockedOrganisations()
    {
        // 1. 准备Mock测试数据
        var mockOrganisations = new List<Organisation>
        {
            new Organisation { Id = 1, Name = "Mock组织1" },
            new Organisation { Id = 2, Name = "Mock组织2" }
        };

        // 2. Mock逻辑仓库,设置无入参方法的返回值
        var mockLogicRepo = new Mock<LogicRepository>();
        mockLogicRepo.Setup(repo => repo.GetAllOrganisations())
                     .Returns(mockOrganisations);

        // 3. 将Mock实例注入控制器
        var controller = new OrganisationController(mockLogicRepo.Object as OrganisationLogic);

        // 4. 执行待测试的控制器方法
        var result = controller.GetAll();

        // 5. 断言结果符合预期
        var okResult = Assert.IsType<OkObjectResult>(result);
        var returnedOrgs = Assert.IsType<List<Organisation>>(okResult.Value);
        Assert.Equal(2, returnedOrgs.Count);
        Assert.Equal("Mock组织1", returnedOrgs[0].Name);

        // 可选:验证目标方法是否被调用过一次
        mockLogicRepo.Verify(repo => repo.GetAllOrganisations(), Times.Once);
    }
}

3. 核心要点说明

  • 优先Mock抽象类:尽量MockLogicRepository而非具体的OrganisationLogic,这样测试不会耦合业务层的实现细节,扩展性更强。
  • 无入参方法的Setup:直接通过Setup(repo => repo.GetAllOrganisations())指定要Mock的方法,再用Returns()设置自定义返回值即可,无需参数匹配器。
  • 验证方法调用:如果需要确认控制器确实调用了业务层方法,可以用Verify()方法校验调用次数。

内容的提问来源于stack exchange,提问作者Steve Westgarth

火山引擎 最新活动