单元测试中如何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抽象类:尽量Mock
LogicRepository而非具体的OrganisationLogic,这样测试不会耦合业务层的实现细节,扩展性更强。 - 无入参方法的Setup:直接通过
Setup(repo => repo.GetAllOrganisations())指定要Mock的方法,再用Returns()设置自定义返回值即可,无需参数匹配器。 - 验证方法调用:如果需要确认控制器确实调用了业务层方法,可以用
Verify()方法校验调用次数。
内容的提问来源于stack exchange,提问作者Steve Westgarth




