Jest.js 如何模拟/测试NestJS服务对仓库的调用?

sigwle7e  于 11个月前  发布在  Jest
关注(0)|答案(1)|浏览(168)

我有一个NestJS服务,它有一个非常简单的方法,我正试图为其编写单元测试

@Injectable()
export class TestService {

  constructor(
    @InjectRepository(TestEntity)
    private readonly repo: Repository<TestEntity>,
  ) {}

  async getAllTests(acct: AccountEntity): Promise<Array<TestEntity>> {
    try {
      const query = this.repo.createQueryBuilder(DB_TABLE_NAME_TEST);
      query.where({ account: acct.id });

      return await query.getMany();
    } catch (ex) {
      throw new InternalServerErrorException();
    }
  }
}

字符串
并且此检验

const mockAccount: AccountEntity = {
  id: 'mock-account-id-1234',
  email: '[email protected]',
};

const mockTest: TestEntity = {
  id: '1234-5678-9012',
  account: 'mock-account-id-1234',
  description: 'Test Name',
  testerName: 'Bob Jones',
  testerEmail: '[email protected]',
};

describe('TestService', () => {
  let service: TestService;
  let repo: Repository<TestEntity>;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        TestService,
        {
          provide: getRepositoryToken(TestEntity),
          useValue: {
            create: jest.fn(),
            save: jest.fn(),
            delete: jest.fn(),
            createQueryBuilder: jest.fn(() => ({
              where: jest.fn(),
              getMany: jest.fn(),
              getOne: jest.fn(),
            })),
          },
        },
      ],
    }).compile();

    service = module.get(TestService);
    repo = module.get(getRepositoryToken(TestEntity));
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  describe('getAllTests()', () => {
    it('should successfully get a list of all tests for the provided account', async () => {
      jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'where')
      jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'getMany').mockResolvedValue([mockTest]);

      expect(repo.createQueryBuilder(DB_TABLE_NAME_TEST).where).toHaveBeenCalledWith({ account: mockAccount.id });
      await expect(service.getAllTests(mockAccount)).resolves.toEqual([mockTest]);
    });

    it('should throw an error when the query fails', async () => {
      jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'where').mockImplementation(() => {
        throw new Error();
      });

      jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'getMany').mockImplementation(() => {
        throw new Error();
      });

      const result = () => service.getAllTests(mockAccount);
      await expect(result).rejects.toThrow(InternalServerErrorException);
    });
  });
});


getAllTests()方法的这两个测试都失败了:

FAIL  src/test/test.service.spec.ts
  ● TestService › getAllTests() › should successfully get a list of all tests for the provided account

    expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: {"account": "mock-account-id-1234"}

    Number of calls: 0

      143 |       jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'getMany').mockResolvedValue([mockTest]);
      144 |
    > 145 |       expect(repo.createQueryBuilder(DB_TABLE_NAME_TEST).where).toHaveBeenCalledWith({ account: mockAccount.id });
          |                                                                 ^
      146 |       await expect(service.getAllTests(mockAccount)).resolves.toEqual([mockTest]);
      147 |     });
      148 |

      at Object.<anonymous> (test/test.service.spec.ts:145:65)

  ● TestService › getAllTests() › should throw an error when the query fails

    expect(received).rejects.toThrow()

    Received promise resolved instead of rejected
    Resolved to value: undefined

      157 |
      158 |       const result = () => service.getAllTests(mockAccount);
    > 159 |       await expect(result).rejects.toThrow(InternalServerErrorException);
          |             ^
      160 |     });
      161 |   });
      162 | });

      at expect (../node_modules/expect/build/index.js:113:15)
      at Object.<anonymous> (test/test.service.spec.ts:159:13)


这看起来应该很简单,我做错了什么?

kknvjkwl

kknvjkwl1#

在第一个测试中,您Assertmock.where to在 * 调用服务之前 * 被调用。此外每次调用createQueryBuilder时,你会得到一个全新的.where和一个新的jest.fn()跟踪对它的调用。我建议你在这里做的是创建一个单独的const whereMock = jest.fn().mockReturnThis(),这样你就可以在createQueryBuilder对象中设置where: whereMock。这将允许您在Assert调用where时访问正确的jest.fn()
在第二个测试中,同样因为createQueryBuilder是一个jest.fn(),所以对它的每个调用都返回一个新对象,所以你的jest.spyOn调用并没有监视服务正在使用的同一个对象。为了克服这个问题,你可以像我建议的那样为whereMock创建mock,这样它们就可以直接引用,而不必通过新对象。

相关问题