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

使用Jest模拟Azure SDK的PagedAsyncIterableIterator时byPage调用失败排查

Jest模拟Azure SDK的PagedAsyncIterableIterator时.byPage()调用失败问题

我在使用Jest模拟Azure SDK的PagedAsyncIterableIterator时,单元测试调用.byPage()方法失败,报错TypeError: this.storageManagementClient.localUsersOperations.list(...).byPage is not a function。list方法的模拟能正常运行,但调用list()后的.byPage()子方法失效。


业务代码

async findAll(accountId: number): Promise<Array<SftpUserResponseDto>> {

    // ...
    // Get a list of Users from the Azure SFTP Blob Account
    const localUserPages = this.storageManagementClient.localUsersOperations
      .list(this.resourceGroup, this.storageAccount)
      .byPage();

    for await (const page of localUserPages) {
      // Do stuff with the list of Users on the page
    }
    // ...
}

单元测试代码

describe('SftpUsersService', () => {
 let mockStorageManagementClient: Partial<StorageManagementClient>;
 beforeEach(async () => {
    mockStorageManagementClient = {
      localUsersOperations: {
        delete: jest.fn(),
        list: jest.fn().mockResolvedValue(sftpUsersMocks.listPage),
        createOrUpdate: jest.fn().mockResolvedValue(sftpUsersMocks.localUser1),
        get: jest.fn().mockResolvedValue(sftpUsersMocks.localUser1),
        listKeys: jest.fn(),
        regeneratePassword: jest.fn(),
      },
    };

  const module: TestingModule = await Test.createTestingModule({
      providers: [
        // ...
        {
          provide: StorageManagementClient,
          useValue: mockStorageManagementClient,
        },
      ],
    }).compile(); 
  };
  // ...
});
describe('findAll', () => {
    it('should return a list of users', async () => {
      const accountId = sftpUsersMocks.account1.accountId;

      const users = await service.findAll(accountId);

      expect(users).toEqual(sftpUsersMocks.listResponse);
      expect(
        mockStorageManagementClient.localUsersOperations.list,
      ).toHaveBeenCalledWith(accountId);
    });
  });
});

模拟对象代码

export class SftpUsersMocks {

  listPage: PagedAsyncIterableIterator<LocalUser, LocalUser[], PageSettings> = {
    byPage: jest.fun(),
    [Symbol.asyncIterator]: jest.fn(),
    next: jest.fn(),
  };
};

尝试过的替代方案

我还试过直接在list的mock里返回带byPage的对象,但依然无效:

mockStorageManagementClient = {
  localUsersOperations: {
    delete: jest.fn(),
    list: jest.fn().mockResolvedValue({
      byPage: jest.fn(),
    }),
  },
};

问题原因与解决方法

核心问题

Azure SDK的list方法不返回Promise,而是直接返回PagedAsyncIterableIterator对象。你当前用mockResolvedValue把它模拟成了Promise,导致业务代码里调用.list(...).byPage()时,实际是在Promise实例上调用方法,自然找不到byPage。

修复步骤

  1. 替换mock方法:把mockResolvedValue改成mockReturnValue,直接返回模拟的迭代器对象:
// 在beforeEach的localUsersOperations里修改list的mock
list: jest.fn().mockReturnValue(sftpUsersMocks.listPage),
  1. 修正模拟对象的笔误:jest.fun()是拼写错误,要改成jest.fn(),同时给byPage和异步迭代器返回可遍历的异步生成器,确保for await...of能正常运行:
export class SftpUsersMocks {
  listPage: PagedAsyncIterableIterator<LocalUser, LocalUser[], PageSettings> = {
    byPage: jest.fn().mockReturnValue(async function* () {
      // 模拟分页数据,这里返回你需要的测试数据
      yield sftpUsersMocks.listResponse;
    }()),
    [Symbol.asyncIterator]: jest.fn().mockReturnValue(async function* () {
      yield sftpUsersMocks.listResponse;
    }()),
    next: jest.fn(),
  };
};

修改后,业务代码调用list(...).byPage()时,拿到的就是带正确方法的模拟迭代器,单元测试即可正常执行。


内容的提问来源于stack exchange,提问作者S.S.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:05:09