多迈知识库
第二套高阶模板 · 更大气的阅读体验

MVVM模式单元测试实战指南

发布时间:2025-12-10 21:23:26 阅读:314 次

MVVM模式单元测试实战指南

做前端开发这些年,碰过不少架构坑。刚接手一个用MVVM模式写的项目时,最头疼的不是逻辑复杂,而是改完代码不知道有没有搞出新问题。后来尝到了单元测试的甜头,尤其是给MVVM结构写测试,心里踏实多了。

为什么MVVM适合单元测试

MVVM把界面(View)和数据逻辑(ViewModel)拆得清清楚楚。ViewModel不依赖DOM,只管状态和行为,这正好是单元测试最喜欢的类型——纯逻辑、无副作用。比如你写了个购物车功能,点击“结算”按钮前要检查是否登录,这个判断完全可以脱离页面跑测试。

以前团队里有人改了登录状态的字段名,结果首页购物车按钮一直显示“请登录”,其实用户早就登上了。加了测试之后,这种低级错误再也没跑过上线环境。

怎么给ViewModel写测试

以Vue为例,假设你有个简单的表单ViewModel:

const userForm = {
  data() {
    return {
      name: '',
      age: null
    };
  },
  computed: {
    isValid() {
      return this.name && this.age >= 18;
    }
  },
  methods: {
    reset() {
      this.name = '';
      this.age = null;
    }
  }
};

对应的测试可以直接调用方法、检查计算属性:

it('表单验证应正确判断有效性', () => {
  const form = userForm.data();
  form.name = 'Alice';
  form.age = 20;
  expect(userForm.computed.isValid.call(form)).toBe(true);

  form.age = 17;
  expect(userForm.computed.isValid.call(form)).toBe(false);
});

Mock服务接口避免网络依赖

真实项目里ViewModel常要调API。测试时可不想真发请求,这时候就得mock。比如登录逻辑调了api.login(credentials),可以在测试里替换成假响应:

jest.mock('../api', () => ({
  login: jest.fn().mockResolvedValue({ token: 'fake-token' })
}));

这样测“点击登录后token是否保存”就快多了,还不怕接口临时下线影响本地开发。

别忘了监听和事件的测试

ViewModel经常用$emit往外抛事件,比如保存成功后通知父组件刷新列表。这类逻辑也要覆盖:

it('保存成功应触发saved事件', () => {
  const mockEmit = jest.fn();
  const vm = createComponent({ $emit: mockEmit });
  vm.save();
  expect(mockEmit).toHaveBeenCalledWith('saved', expect.any(Object));
});

这种测试写多了,重构的时候手就不抖了。哪怕把“保存”改成“提交”,只要行为不变,测试照样过。

自动化集成到配置流程

光写测试没用,得让它自动跑。我们在CI配置里加了一行:npm run test:unit,每次提交代码都会执行。新人提交的代码如果没过测试,连合并按钮都点不了。刚开始大家嫌烦,后来发现省了半夜修bug的时间,反而主动写测试了。

软件配置不只是配环境变量和部署脚本,把测试纳入流程,才是让代码长期稳定的正路。