graphql tools_使用graphql-tools +模拟GraphQL

graphql tools

如何使用实际值模拟GraphQL API (How to mock up your GraphQL API with realistic values)

In my last article, I took the original Apollo LaunchPad Posts and Authors API and broke it down into domains and components. I wanted to illustrate how one could organize a large GraphQL project using graphql-tools.

上一篇文章中,我采用了原始的Apollo LaunchPad Posts and Authors API,并将其细分为域和组件。 我想说明一个人如何使用graphql-tools组织一个大型GraphQL项目。

Now I’d like the API to return mock data when I query it. How?

现在,我希望API在查询时返回模拟数据。 怎么样?

原始资料 (The original source)

In the original Apollo Launchpad example, we used static data structures and simple mapping resolvers to provide output for queries.

在原始的Apollo Launchpad示例中,我们使用了静态数据结构和简单的映射解析器来提供查询的输出。

For instance, given this query:

例如,给定此查询:

# Welcome to GraphiQL

query PostsForAuthor {
  author(id: 1) {
    firstName
    posts {
      title
      votes
    }
  }
}

The output would be:

输出为:

{
  "data": {
    "author": {
      "firstName": "Tom",
      "posts": [
        {
          "title": "Introduction to GraphQL",
          "votes": 2
        }
      ]
    }
  }
}

The resolvers object has functions that take care of mapping authors to posts and visa-versa. It’s not truly a mock, though.

解析器对象具有负责将作者映射到帖子,反之亦然的功能。 但是,这并不是真正的模拟。

The problem is that the more relationships and the more complex the entities become, the more code needs to go into the resolvers. Then more data needs to be provided.

问题在于,实体之间的关系越多,越复杂,则需要更多的代码输入解析器。 然后,需要提供更多数据。

When it comes to testing, tests are likely to sometimes reveal problems in the data or in the resolvers. You really want focus testing of the API itself.

对于测试,测试有时可能会揭示数据或解析器中的问题。 您确实要对API本身进行焦点测试。

使用模拟 (Using mocks)

There are three Node.js modules that make mocking an API quick and easy. The first is part of the graphql-tools module. Using this module, a beginning step is to require or import the method addMockFunctionsToSchema from the module into the root schema.js file:

通过三个Node.js模块,可以快速轻松地模拟API。 首先是graphql-tools 模块。 使用此模块,第一步是要求或导入方法addMockFunctionsToSchema 从模块到根schema.js文件:

import {
    makeExecutableSchema,
    addMockFunctionsToSchema
} from 'graphql-tools';

Then, after creating an executable schema by calling createExecutableSchema, you add your mocks like so:

然后,在通过调用createExecutableSchema创建可执行schema之后, 您可以这样添加模拟:

addMockFunctionsToSchema({
        schema: executableSchema,
    })

Here’s a full listing of the root schema.js:

这是根schema.js的完整列表:

So what’s the output? Executing the same query as before yields:

那么输出是什么? 执行与之前相同的查询会产生:

{
  "data": {
    "author": {
      "firstName": "Hello World",
      "posts": [
        {
          "title": "Hello World",
          "votes": -70
        },
        {
          "title": "Hello World",
          "votes": -77
        }
      ]
    }
  }
}

Well, that’s kind of dumb. Every string is “Hello World”, votes are negative, and there will always be exactly two posts per author. We’ll fix that, but first…

好吧,这真是愚蠢。 每个字符串都是“ Hello World”,票数是否定的,每个作者始终只有两个帖子。 我们将解决此问题,但首先…

为什么要使用模拟? (Why use mocks?)

Mocks are often used in unit tests to separate the functionality being tested from the dependencies that those functions rely on. You want to test the function (the unit), not a whole complex of functions.

模拟通常用于单元测试中,以将要测试的功能与这些功能所依赖的依赖项区分开。 您要测试功能(单元),而不是功能的整体。

At this early stage of development, mocks serve another purpose: to test the tests. In a basic test, you want to ensure first that the test is calling the API correctly, and that the results returned have the expected structure, properties, and types. I think the cool kids call this “shape”.

在开发的早期阶段,模拟服务的另一个目的是:测试测试。 在基本测试中,您首先要确保测试正确调用了API,并且返回的结果具有预期的结构,属性和类型。 我认为很酷的孩子称之为“形状”。

This offers more limited testing than a queryable data structure, because reference semantics are not enforced. id is meaningless. Nonetheless, mocks offer something to structure your tests around

与可查询的数据结构相比,这提供了更多有限的测试,因为没有强制执行引用语义。 id是没有意义的。 尽管如此,模拟还是提供了一些结构化测试的方法

现实的嘲笑 (Realistic mocking)

There’s a module called casual that I really like. It provides reasonable and variable values for a lot of common data types. If you are demonstrating your new API in front of jaded colleagues, it actually looks like you’ve done something special.

我真的很喜欢一个叫做休闲的模块。 它为许多常见数据类型提供了合理且可变的值。 如果您是在厌倦的同事面前演示新的API,那么实际上看起来您已经做了一些特别的事情。

Here’s a wish list for mock values to display:

这是要显示的模拟值的愿望清单:

  1. Author’s first name should be first-name-like

    作者的名字应该像名字一样

  2. Post titles should be variable lorem ipsum text of limited length

    帖子标题应为长度有限的可变lorem ipsum文本

  3. votes should be positive or zero

    票数应为正数或零
  4. the number of posts should vary between 1 and 7

    帖子数应在1到7之间变化

First thing is to create a folder called mocks. Next, we’ll add an index.js file to that folder with the mock methods. Finally, the custom mocks will be added to the generated executable schema.

第一件事是创建一个名为mocks的文件夹。 接下来,我们将使用模拟方法将index.js文件添加到该文件夹​​。 最后,自定义模拟将添加到生成的可执行模式中。

The casual library can generate values by data type (String, ID, Int, …) or by property name. Also, graphql-tools MockList object will be used to vary the number of items in a list — in this case posts. So let’s start.

临时库可以按数据类型( String, ID, Int, … )或属性名称生成值。 此外,graphql-tools MockList对象将用于更改列表中的项目数(在本例中为posts 。 因此,让我们开始吧。

Import both casual and MockList into /mocks/index.js:

Import既休闲又MockList到/mocks/index.js

import casual from 'casual';
import {
    MockList
} from 'graphql-tools';

Now let create a default export with the following properties:

现在,创建具有以下属性的默认导出:

export default {
    Int: () => casual.integer(0),
    
    Author: () => ({
        firstName: casual.first_name,
        posts: () => new MockList([1, 7])
    }),
    
    Post: () => ({
        title: casual.title
    })
}

The Int declaration takes care of all integer types appearing in our schema and it will ensure that Post.votes will be positive or zero.

Int声明会处理出现在我们架构中的所有整数类型,并确保Post.votes为正数或零。

Next, Author.firstName will be a reasonable first name. MockList is used to ensure the number of posts associated with each Author will be between 1 and 7. Finally, casual will generate a lorem ipsum title for each Post.

接下来, Author.firstName将是一个合理的名字。 MockList用于确保与每个Author相关的帖子数量在1到7之间。最后,Casual将为每个Post生成一个lorem ipsum title

Now the generated output varies each time the query is executed. And it looks credible:

现在,每次执行查询时,生成的输出都会变化。 而且看起来很可信:

{
  "data": {
    "author": {
      "firstName": "Eldon",
      "posts": [
        {
          "title": "Voluptatum quae laudantium",
          "votes": 581
        },
        {
          "title": "Vero quos",
          "votes": 85
        },
        {
          "title": "Doloribus labore corrupti",
          "votes": 771
        },
        {
          "title": "Qui nulla qui",
          "votes": 285
        }
      ]
    }
  }
}

生成自定义值 (Generating custom values)

I just scratched the surface of what casual can do, but it is well-documented and there’s nothing much to add.

我只是简单介绍了随便可以做什么,但有据可查,没有什么可补充的。

Sometimes, though, there are values that have to conform to a standard format. I would like to introduce one more module: randexp.

但是,有时某些值必须符合标准格式。 我想再介绍一个模块: randexp

randexp allows you to generate values conforming to the regexp expression you provide it. For instance, ISBN numbers have the format:

randexp允许您生成符合您提供的regexp表达式的值。 例如,ISBN号具有以下格式:

/ISBN-\d-\d{3}-\d{5}-\d/

/ ISBN- \ d- \ d {3}-\ d {5}-\ d /

Now I can add Books to the schema, add books to Author, and generate ISBN and title for each Book:

现在,我可以将Books添加到架构中,将book添加到Author中,并为每个Book生成ISBN和书名:

// book.js
export default `
  type Book {
    ISBN: String
    title: String
}

mocks.js:

mocks.js:

import casual from 'casual';
import RandExp from 'randexp';
import {
    MockList
} from 'graphql-tools';
import {
    startCase
} from 'lodash';

export default {
    Int: () => casual.integer(0),
    
Author: () => ({
        firstName: casual.first_name,
        posts: () => new MockList([1, 7]),
        books: () => new MockList([0, 5])
    }),
    
Post: () => ({
        title: casual.title
    }),
    
Book: () => ({
        ISBN: new RandExp(/ISBN-\d-\d{3}-\d{5}-\d/)
            .gen(),
        title: startCase(casual.title)
    })
}

And here’s a new query:

这是一个新查询:

query PostsForAuthor {
  author(id: 1) {
    firstName
    posts {
      title
      votes
    }
    books {
      title
      ISBN
    }
  }
}

Sample response:

样本回复:

{
  "data": {
    "author": {
      "firstName": "Rosemarie",
      "posts": [
        {
          "title": "Et ipsum quo",
          "votes": 248
        },
        {
          "title": "Deleniti nihil",
          "votes": 789
        },
        {
          "title": "Aut aut reprehenderit",
          "votes": 220
        },
        {
          "title": "Nesciunt debitis mollitia",
          "votes": 181
        }
      ],
      "books": [
        {
          "title": "Consequatur Veniam Voluptas",
          "ISBN": "ISBN-0-843-74186-9"
        },
        {
          "title": "Totam Et Iusto",
          "ISBN": "ISBN-6-532-70557-3"
        },
        {
          "title": "Voluptatem Est Sunt",
          "ISBN": "ISBN-2-323-13918-2"
        }
      ]
    }
  }
}

So that’s the basics of mocking using graphql-tools plus a couple of other useful modules .

这就是使用graphql-tools以及其他几个有用模块进行模拟的基础。

Note: I use snippets throughout this post. If you want to follow along in a broader context, sample code is here.

注意 :在本文中,我都会使用摘要。 如果你想沿着更广的范围内遵循,示例代码是在这里

The Full source is on GitHub for your perusal.

完整的源代码在GitHub上供您阅读。

Give me a hand if you found this article informative.

如果您发现本文内容丰富,请给我帮助。

翻译自: https://www.freecodecamp.org/news/mocking-graphql-with-graphql-tools-42c2dd9d0364/

graphql tools

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值