智享技巧屋
第二套高阶模板 · 更大气的阅读体验

依赖注入在单元测试中的实用技巧

发布时间:2025-12-21 18:51:01 阅读:195 次

写代码时,谁还没碰上过那种改一处、崩一片的情况?尤其是做安全软件开发,逻辑复杂、模块交错,测一个功能得先把数据库连上、网络通了、配置文件配好,光准备环境就得半小时。这时候,依赖注入(DI)加单元测试的组合就派上大用场了。

为什么依赖注入让测试更轻松

想象一下你在写一个用户登录模块,里面直接 new 了一个数据库连接类。想测登录逻辑?不好意思,得先起个数据库。可要是通过构造函数把数据库操作作为依赖传进来,测试时就能塞一个“假”的数据库实现进去——不连真实服务,只返回预设数据。这样测的是逻辑本身,而不是整个系统。

依赖注入的核心就是“别自己创建依赖,让别人给你”。这样一来,运行时给真对象,测试时给假对象(mock),隔离性拉满。

一个简单的例子

比如有这么一个类,负责检查用户是否有权限访问某个资源:

public class AccessControl {
    private IUserRepository _userRepository;

    public AccessControl(IUserRepository userRepository) {
        _userRepository = userRepository;
    }

    public bool HasAccess(string userId, string resource) {
        var user = _userRepository.FindById(userId);
        if (user == null) return false;
        return user.Role == "admin" || user.AllowedResources.Contains(resource);
    }
}

现在要写单元测试,完全不需要真实用户数据。可以用 Moq 这样的库造个假的 IUserRepository

[TestMethod]
public void AdminUser_CanAccessAnyResource() {
    // Arrange
    var mockRepo = new Mock<IUserRepository>();
    mockRepo.Setup(r => r.FindById("u123"))
            .Returns(new User { Role = "admin", AllowedResources = new List<string>() });

    var control = new AccessControl(mockRepo.Object);

    // Act
    bool result = control.HasAccess("u123", "/delete-all");

    // Assert
    Assert.IsTrue(result);
}

这个测试跑起来飞快,不依赖任何外部系统,还能精准覆盖边界情况,比如用户为空、权限不足等。

对安全软件的意义

安全相关的代码往往涉及权限校验、行为拦截、日志记录等关键路径。一旦出错,轻则功能失效,重则留下漏洞。用依赖注入配合单元测试,能把这些核心逻辑拆出来单独验证。比如审计模块是否正确记录了敏感操作,不需要真的去触发一次攻击,只要 mock 相关服务,验证调用记录就行。

而且,这样的代码结构更清晰。每个类职责明确,依赖一目了然,新人接手也不容易踩坑。长期维护中,重构也更有底气——只要测试全过,基本不怕改坏。

实际项目里,见过太多把各种服务直接 new 在方法里的写法。结果一写测试就卡住,最后干脆不写了。慢慢地,代码越来越僵,没人敢动。而从一开始就用依赖注入,其实是给自己留条退路,也是给团队留份安心。