MST

星途 面试题库

面试题:C# 测试驱动开发中如何处理依赖注入

在 C# 的测试驱动开发场景下,假设你有一个复杂业务逻辑类,依赖多个其他服务接口。请描述如何通过依赖注入的方式,使得该类在单元测试中能够被有效测试,并且说明使用依赖注入进行测试的好处。
29.1万 热度难度
编程语言C#

知识考点

AI 面试

面试题答案

一键面试

实现步骤

  1. 定义接口:为依赖的每个服务定义接口。例如,如果复杂业务逻辑类 ComplexBusinessLogic 依赖用户服务和订单服务,分别定义 IUserServiceIOrderService 接口,接口中声明业务逻辑类会调用的方法。
public interface IUserService
{
    User GetUserById(int id);
}

public interface IOrderService
{
    Order GetOrderById(int id);
}
  1. 在复杂业务逻辑类中通过构造函数注入依赖:修改 ComplexBusinessLogic 类,通过构造函数接受依赖的接口实例。
public class ComplexBusinessLogic
{
    private readonly IUserService _userService;
    private readonly IOrderService _orderService;

    public ComplexBusinessLogic(IUserService userService, IOrderService orderService)
    {
        _userService = userService;
        _orderService = orderService;
    }

    public void SomeComplexMethod()
    {
        // 使用 _userService 和 _orderService 完成复杂业务逻辑
        var user = _userService.GetUserById(1);
        var order = _orderService.GetOrderById(1);
        // 进一步处理逻辑
    }
}
  1. 在单元测试中创建模拟对象并注入:使用如 Moq 这样的模拟框架,在单元测试中创建模拟的服务接口实例,并通过构造函数注入到 ComplexBusinessLogic 实例中。
using Moq;
using NUnit.Framework;

[TestFixture]
public class ComplexBusinessLogicTests
{
    [Test]
    public void TestSomeComplexMethod()
    {
        var mockUserService = new Mock<IUserService>();
        var mockOrderService = new Mock<IOrderService>();

        mockUserService.Setup(s => s.GetUserById(1)).Returns(new User());
        mockOrderService.Setup(s => s.GetOrderById(1)).Returns(new Order());

        var complexLogic = new ComplexBusinessLogic(mockUserService.Object, mockOrderService.Object);

        complexLogic.SomeComplexMethod();

        mockUserService.Verify(s => s.GetUserById(1), Times.Once);
        mockOrderService.Verify(s => s.GetOrderById(1), Times.Once);
    }
}

好处

  1. 解耦依赖:复杂业务逻辑类不再直接依赖具体的服务实现,降低了类与类之间的耦合度,提高了代码的可维护性和可扩展性。例如,当 IUserService 的具体实现发生变化时,只要接口不变,ComplexBusinessLogic 类不需要修改。
  2. 便于单元测试:可以创建模拟对象来替换真实的依赖服务,使得测试可以专注于复杂业务逻辑类本身的功能,避免了因依赖服务的不可用或不稳定导致测试失败。例如,在上述测试中,不依赖真实的用户服务和订单服务即可测试 ComplexBusinessLogicSomeComplexMethod 方法。
  3. 提高代码的可复用性:由于依赖通过接口注入,不同的业务场景可以使用不同的实现来满足依赖,提高了代码的复用性。例如,在不同的模块中,只要实现了 IUserService 接口,都可以注入到依赖该接口的类中。