GraphQL解析器测试的详细指南

97 阅读2分钟

我们将测试以下GraphQL解析器,它有授权和许可检查。如果用户没有经过认证,解析器会返回一个错误。如果数据库实体的要求没有得到满足,解析器会返回一个错误。否则,解析器会创建一个新的数据库实体。

export default {
  Mutation: {
    createFreeCourse: async (
      parent,
      { courseId, bundleId },
      { me }
    ) => {
      if (!me) {
        return new Error('Not authenticated as user.');
      }

      const price = getPrice(courseId, bundleId);
      if (price !== 0) {
        return new Error('This course is not for free.')
      }

      await createCourse({
        uid: me.uid,
        courseId,
        bundleId,
        amount: 0,
        paymentType: 'FREE',
      });

      return true;
    },
  },
};

如果我们使用GraphQL解析器中间件(这是可选的),它可以被简化为以下内容。

export default {
  Mutation: {
    createFreeCourse: combine(
      isAuthenticated,
      isFreeCourse,
      async (parent, { courseId, bundleId }, { me }) => {
        await createCourse({
          uid: me.uid,
          courseId,
          bundleId,
          amount: 0,
          paymentType: 'FREE',
        });

        return true;
      }
    ),
  },
};

无论如何,让我们跳到用Jest测试这个GraphQL解析器。我们用所有的参数调用解析器函数,并期望在所有的要求都得到满足时将其返回的承诺解析为真。

import resolvers from './';

describe('createFreeCourse', () => {
  it('creates a course', async () => {
    const result = resolvers.Mutation.createFreeCourse(
      null,
      {
        courseId: 'THE_ROAD_TO_GRAPHQL',
        bundleId: 'STUDENT',
      },
      { me: { uid: '1', email: 'example@example.com' } },
      null
    );

    await expect(result).resolves.toEqual(true);
  });
});

如果你需要用Jest来模拟数据库请求,请查看这个关于Jest模拟的教程。一旦你模拟了你的数据库API,你可以在你的测试案例中添加更多的断言。

import resolvers from './';

describe('createFreeCourse', () => {
  it('creates a course', async () => {
    const result = resolvers.Mutation.createFreeCourse(
      null,
      {
        courseId: 'THE_ROAD_TO_GRAPHQL',
        bundleId: 'STUDENT',
      },
      { me: { uid: '1', email: 'example@example.com' } },
      null
    );

    await expect(result).resolves.toEqual(true);

    expect(mockedSet).toHaveBeenCalledTimes(1);

    expect(mockedSet).toHaveBeenCalledWith({
      courseId: 'THE_ROAD_TO_GRAPHQL',
      packageId: 'STUDENT',
      invoice: {
        createdAt: 'TIMESTAMP',
        amount: 0,
        licensesCount: 1,
        currency: 'USD',
        paymentType: 'FREE',
      },
    });
  });
});

不管怎样,让我们保持测试用例的简单性,不要有数据库断言。到目前为止,我们只测试了满足所有要求的解析器逻辑的快乐路径。如果用户没有被认证呢?

describe('createFreeCourse', () => {
  it('creates a course', async () => {
    ...
  });

  it('does not create a course if not authenticated', async () => {
    const result = resolvers.Mutation.createFreeCourse(
      null,
      {
        courseId: 'THE_ROAD_TO_GRAPHQL',
        bundleId: 'STUDENT',
      },
      { me: null },
      null
    );

    await expect(result).resolves.toEqual(
      new Error('Not authenticated as user.')
    );
  });
});

通常情况下,我们期望承诺会被拒绝。然而,在 GraphQL 中,我们成功地将错误作为解析结果返回。这样,我们也可以测试 GraphQL 解析器的其他条件逻辑。

describe('createFreeCourse', () => {
  it('creates a course', async () => {
    ...
  });

  it('does not create a course if not authenticated', async () => {
    ...
  });

  it('does not create a course if not free', async () => {
    const result = resolvers.Mutation.createFreeCourse(
      null,
      {
        courseId: 'THE_ROAD_TO_GRAPHQL',
        bundleId: 'PROFESSIONAL',
      },
      { me: { uid: '1', email: 'example@example.com' } },
      null
    );

    await expect(result).resolves.toEqual(
      new Error('This course is not for free.')
    );
  });
});

这就是它。GraphQL解析器最终只是函数。你可以在你的测试文件中导入它们,调用解析器,并执行断言。通过设置授权和许可解析器,你也可以在出错时测试不开心的路径。最后,GraphQL服务器会返回一个承诺,无论是成功的结果还是错误。