You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AsyncWrapper的repoWrap包装后测试报错及返回undefined问题排查

问题解答

问题1:仓库方法包装后返回undefined的原因

核心问题是**repoWrap方法中fn.apply(this)的this指向错误**:

  • 在UserRepository中,findUserById通过this.wrap.repoWrap包装,repoWrap内部调用fn.apply(this)时,此处的this指向AsyncWrapper实例,而非UserRepository实例。
  • 原异步函数依赖UserRepository上下文的this.database,指向错误导致this.database为undefined,数据库查询无法执行,最终返回undefined。

同时测试环节的自动mock也有影响:

  • vi.mock默认仅mock类的原型方法,而findUserById是类的实例属性(箭头函数),自动mock不会为其生成mock实现,调用时自然返回undefined。

修复方案

修改repoWrap,让被包装函数继承原调用上下文:

repoWrap = (fn: Function) => {
  return function(...args: any) { // 改用普通函数保留调用时的this
    return fn.apply(this, args).catch((error: any) => {
      throw DatabaseException.error(error);
    });
  };
};

同时在测试中手动mock实例属性:

beforeEach(() => {
  // 手动将findUserById设为spy并模拟返回值
  UserRepository.prototype.findUserById = vi.fn().mockResolvedValue({ /* 模拟用户数据 */ });
  userRepository = new UserRepository();
  userService = new UserService(userRepository);
});

问题2:toHaveBeenCalled抛出类型错误的原因

  • findUserById是UserRepository的实例属性箭头函数,而非原型方法。
  • vi.mock自动mock类时,仅会将原型上的方法转为spy,实例属性不会被自动处理,因此userRepository.findUserById不是spy对象,调用toHaveBeenCalled会抛出undefined is not a spy的错误。

修复方案

方案1:手动mock实例属性为spy

beforeEach(() => {
  const mockFindUserById = vi.fn();
  // 替换类的实例属性为spy
  UserRepository.prototype.findUserById = mockFindUserById;
  userRepository = new UserRepository();
  userService = new UserService(userRepository);
});

方案2:将仓库方法改为原型方法

class UserRepository implements IUserRepository {
  private database: Kysely<DB>;
  private wrap: AsyncWrapper = new AsyncWrapper();

  constructor() { 
    this.database = db;
    // 在构造函数中绑定上下文并包装
    this.findUserById = this.wrap.repoWrap(this.findUserById.bind(this));
  };

  // 改为原型方法
  public async findUserById(user_id: number): Promise<SelectUsers | undefined> {
    return await this.database
      .selectFrom("users")
      .where("user_id", "=", user_id)
      .selectAll()
      .executeTakeFirst();
  }
};

修改后vi.mock会自动将其转为spy,测试时可正常调用toHaveBeenCalled断言。


内容的提问来源于stack exchange,提问作者Almighty Dee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 01:52:02