GraphQL과의 통합 테스트

최근 몇 년 동안 GraphQL은 REST 체계 구조의 첫 번째 대체 방안 중 하나가 되었다. 그 많은 장점으로 인해 개발자들이 필요한 데이터만 요청하면 GraphQL의 인기가 날로 증가하고 있다.
테스트는 소프트웨어 응용 프로그램의 기능을 평가하는 과정으로 우리 소프트웨어의 문제나 결함을 발견하거나 ANSI/IEEE 1059 표준 - 소프트웨어 항목을 분석하는 과정에 따라 기존 조건과 필요한 조건(즉 결함) 간의 차이를 측정하고 소프트웨어 항목의 특징을 평가하는 데 목적을 둔다.
테스트는 프로젝트의 성공에 매우 중요하다. 코드의 품질을 확보하고 생산에 들어가기 전에 문제를 확정할 수 있다. 그렇지 않으면 코드가 언제든지 중단되고 금요일 자정에 골머리를 앓게 될 것이다😱 , 이런 상황이 발생하지 않도록 하는 가장 좋은 방법은 테스트이다. 테스트는 당신에게 자신감을 주고 코드가 예상대로 작동하도록 하는 것이다. 문제없다.
일부 유형의 자동 테스트, 단원 테스트, 통합, 끝에서 끝까지, 테스트 유형...오늘날, 우리는 통합에 중점을 두겠습니다. 통합은 끝에서 끝까지의 테스트와 단원 테스트 사이의 중간 위치에 있고, 운행 속도는 단원 테스트보다 못하지만, 이것은 당신에게 단원 테스트보다 더 큰 자신감을 주고, 끝에서 끝까지 테스트보다 더 빨리 운행할 것입니다.

설치


이 글에서 GraphQL API를 사용할 것입니다. 이미 가지고 있다면 괜찮습니다. 그렇지 않으면 복제할 수 있습니다.

의존항


git clone https://github.com/Wonder2210/graphql-typescript-pg-server.git
테스트 전에 제출 서명
git checkout bdcf9de8b42ce81eaa2d11683be1e399e030b7ed
그런 다음 패키지를 설치해야 합니다.
yarn add -D jest @jagi/jest-transform-graphql ts-jest apollo-graphql-test knex-cleaner
우리는 Jest를 테스트 실행 프로그램으로 사용하고 apollographql 테스트를 사용하여 우리의 검색을 테스트할 것입니다. 이것은 클라이언트를 만들어서 실행할 것입니다. 그리고 모든 테스트를 실행한 후에 knexcleaner를 사용하여 데이터베이스를 정리할 것입니다. 우리는 테스트를 실행할 때마다 같은 결과를 얻거나 다시 말하면 테스트는 복제할 수 있습니다.
주의*: knexcleaner는 typescript를 지원하지 않기 때문에 색인에 다음 줄을 추가해야 합니다.d, 송전 시스템
declare module "knex-cleaner" 

농담


우선, 우리는 테스트와 실행에 필요한 모든 것을 저장할 폴더가 필요하다
mkdir /src/__tests__
mkdir /src/__tests__/utils
Jest는 어떤 파일을 실행할 것인지, 어디에 있는지, 그리고 우리의 모드와 같은 파일을 어떻게 처리할 것인지를 알기 위한 설정이 필요합니다.회사 명
module.exports = {
  testPathIgnorePatterns: ["/node_modules"],
  testMatch:  ["**/?(*.)+(spec|test).[jt]s?(x)"],
  transform: {
    "^.+\\.(j|t)sx?$": ["ts-jest"],
    "\\.(gql|graphql)$": ["@jagi/jest-transform-graphql"],
  },
  moduleFileExtensions: ["ts", "tsx", "js", "gql"],
};
이 예에서 testMatch 테스트를 사용할 파일을 지정합니다. 이것은 모든 파일을 실행할 것을 의미합니다.테스트ts 또는 jsx 또는 tsx...그리고 일부 파일을 어떻게 처리하는지,jest는javascript의 본 컴퓨터이기 때문에, 우리는ts파일 (tsjest 사용) 을 변환해야 합니다.gql 또는.graphql 파일 (@jagi/jest 변환graphql 포함)
우리는 가방에 다음 줄을 추가할 것이다.json
...
"scripts":{
    ...
    "test:integration":"jest /src -c  jest.config.js --forceExit"
    ...
}
...

데이터베이스


우리는 하나의 데이터베이스를 사용하여 테스트를 진행할 것입니다. 당신은 당신의 개발 데이터베이스를 사용할 수 있지만, 가장 좋은 것은 이러한 작업에만 사용되는 데이터베이스입니다
테스트 데이터베이스에 데이터를 삽입합니다. 이를 위해 Knex의 피드를 사용합니다. 이것은 데이터베이스에 데이터를 삽입하는 자동화/프로그래밍 방식입니다.
// src/database/seeds/baseSeed.js
exports.seed = function (knex) {
  // Deletes ALL existing entries
  return knex("users")
    .del()
    .then(function () {
      // Inserts seed entries
      return knex("users").insert([
        {  full_name: "luis", country_code: 58 },
        {  full_name: "jose", country_code: 59 },
        {  full_name: "raul", country_code: 39 },
      ]);
    })
    .then(() => {
      return knex("pets")
        .del()
        .then(function () {
          // Inserts seed entries
          return knex("pets").insert([
            { name: "spot", owner_id: 1, specie: "MAMMALS" },
            { name: "chief", owner_id: 2, specie: "MAMMALS" },
            { name: "king", owner_id: 3, specie: "MAMMALS" },
          ]);
        });
    });
};

또한 서명하지 않은 속성을pet의owner\uid 필드에 추가해야 합니다.pets표를 만드는 과정은 다음과 같습니다.
/migrations/initial_migration.ts
...
.createTable("pets", (table: Knex.CreateTableBuilder) => {
      table.increments("id");
      table.string("name");
      table.integer("owner_id").references("users.id").unsigned().onDelete("CASCADE");
      table.string("specie");
      table.timestamps(true, true);
    });
...
이제 패키지에 다음 줄을 추가합니다.json top 실행 피드
...
"scripts":{
    ...
"test:migrate:up": "knex --knexfile ./src/database/knexfile.ts migrate:latest --env testing",
   "test:seed-db": "knex --knexfile ./src/database/knexfile.ts seed:run --env testing"
    ...
}
...
하면, 만약, 만약...

여기 있다 테스트 서버


테스트를 진행하기 위해서, 우리는 우리의 조회에 서비스를 제공하기 위해 서버가 필요하다
// /src/__tests__/utils.server.ts
import { ApolloServer, Config } from "apollo-server-express";
import Knex from "knex";
import { Model } from "objection";
import dbconfig from "../../database/config";
import DataLoader from "dataloader";
import schema from "../../schema";
import { Pets, Users } from "../../utils/loaders";
import dbCleaner from "knex-cleaner";

const db = Knex(dbconfig["testing"]);
export const startDb = () => {

  Model.knex(db);
};

export const stopDB = () => {
  Model.knex().destroy();
};

export const cleanDb= async ()=>{
  const options = {
    mode: 'truncate', 
    restartIdentity: true, 
  }
 return await dbCleaner.clean(db,options);
}

const config: Config = {
  schema: schema,
  context: {
    loaders: {
      users: new DataLoader(Users),
      pets: new DataLoader(Pets),
    },
  },
};

export const server: () => ApolloServer = () => new ApolloServer(config);

조회


Graphql은 쿼리를 사용하여 데이터를 검색합니다. 따라서 이것은 우리가 테스트해야 할 내용입니다. 쿼리는 Graphql Played에서 이미 사용한 내용입니다. 그러나 지금은 자동화 테스트에서 사용할 수 있도록 파일에서 사용해야 합니다.
/__tests__/utils/queries.ts
import gql from "graphql-tag";

export const GET_USERS = gql`
  query getUsers {
    users {
      id
      full_name
      country_code
    }
  }
`;

export const GET_USERS_AND_PETS = gql`
  query getUsersAndItsPets {
    users {
      id
      full_name
      country_code
      pets {
        id
        name
        specie
      }
    }
  }
`;

export const GET_PETS = gql`
  query getPets {
    pets {
      id
      name
      owner_id
      specie
    }
  }
`;

export const CREATE_USER = gql`
  mutation CreateUser($name: String!, $country_code: String!) {
    createUser(user: { full_name: $name, country_code: $country_code }) {
      id
      full_name
      country_code
    }
  }
`;
export const CREATE_PET = gql`
  mutation CreatePet($name: String!, $owner_id: Int!, $specie: Species!) {
    createPet(pet: { name: $name, owner_id: $owner_id, specie: $specie }) {
      id
      name
      specie
    }
  }
`;

export const DELETE_PET = gql`
  mutation DeletePet($id: Int!) {
    deletePet(id: $id) {
      String
    }
  }
`;

export const DELETE_USER = gql`
  mutation DeleteUser($id: Int!) {
    deleteUser(id: $id)
  }
`;

export const UPDATE_USER = gql`
  mutation UpdateUser($id: Int!, $name: String, $country_code: String) {
    updateUser(
      user: { id: $id, full_name: $name, country_code: $country_code }
    ) {
      id
      full_name
      country_code
    }
  }
`;

export const UPDATE_PET = gql`
  mutation UpdatePet($id: Int!, $name: String!) {
    updatePet(pet: { id: $id, name: $name }) {
      id
      name
      owner_id
    }
  }
`;

보시다시피 우리는 API에서 거의 모든 조회를 사용합니다
지금 우리는 그것들을 실행하기 위해 클라이언트가 필요하다.

고객


클라이언트에 대해 우리는apollo 서버 테스트를 사용할 것입니다. "클라이언트"를 만들어서 서버에서 조회를 실행할 수 있도록 합니다

테스트를 작성해 보도록 하겠습니다.😄


이 경우, 우리는 필드 A에 B가 포함되어 있는지 테스트할 생각이 없습니다. 아니요, 정확히 말하자면, 우리는 스냅샷을 사용할 것입니다. 스냅샷을 통해 우리는 조회 결과를 포착할 수 있습니다. 이 필드를 통해 서버의 결과를 볼 수 있고, 그들이 정상적인지, 아니면 우리가 스냅샷 테스트를 할 때 고장이 났는지 검사할 수 있습니다. 마지막 스냅샷과 일치한다면 테스트는 성공할 것입니다.따라서 새 기능을 추가하거나 데이터가 변경되면 스냅샷을 업데이트해야 합니다. 그렇지 않으면 테스트에 실패합니다.
우선, 우리는 필요한 조회와 라이브러리를 가져오고, 테스트를 실행하기 전과 이후에 실행할 조작을 설정합니다
import { server, startDb, cleanDb } from "./utils/server";
import { createTestClient } from "apollo-server-testing";
import {
  GET_USERS,
  GET_PETS,
  GET_USERS_AND_PETS,
  CREATE_USER,
  CREATE_PET,
  UPDATE_USER,
  DELETE_USER,
} from "./utils/queries";

beforeAll(() => {
  return startDb(); // here we are starting the database before the tests run
});
afterAll(()=>{
  return cleanDb(); // with that we are cleaning the database after all the tests have been executed
})
이제 우리의 테스트는 다음과 같다.


test("query users", async () => {
  const serverTest = server();// start our tests server
  const { query } = createTestClient(serverTest); // start our client passing our server as parameter and taking the query function from it

  const res = await query({ query: GET_USERS });// we execute our query

  expect(res).toMatchSnapshot();// we get the result and create or compare the snapshot 
});
우리의 전체 테스트는 다음과 같다.
//  /src/__tests__/integration.test.ts
import { server, startDb, cleanDb } from "./utils/server";
import { createTestClient } from "apollo-server-testing";
import {
  GET_USERS,
  GET_PETS,
  GET_USERS_AND_PETS,
  CREATE_USER,
  CREATE_PET,
  UPDATE_USER,
  DELETE_USER,
} from "./utils/queries";

beforeAll(() => {
  return startDb(); // here we are starting the database before every test run
});
afterAll(()=>{
  return cleanDb(); // with that we are cleaning our database after all the tests have run 
})

test("query users", async () => {
  const serverTest = server();
  const { query } = createTestClient(serverTest);

  const res = await query({ query: GET_USERS });

  expect(res).toMatchSnapshot();
});

test("query pets", async () => {
  const serverTest = server();
  const { query } = createTestClient(serverTest);

  const res = await query({ query: GET_PETS });

  expect(res).toMatchSnapshot();
});

test("query users and its pets", async () => {
  const serverTest = server();
  const { query } = createTestClient(serverTest);

  const res = await query({ query: GET_USERS_AND_PETS });

  expect(res).toMatchSnapshot();
});

test("create user ", async () => {
  const serverTest = server();
  const { mutate } = createTestClient(serverTest);

  const res = await mutate({
    mutation: CREATE_USER,
    variables: {
      name: "Wonder",
      country_code: "ve",
    },
  });

  expect(res).toMatchSnapshot();
});

test("create pet", async () => {
  const serverTest = server();
  const { mutate } = createTestClient(serverTest);

  const res = await mutate({
    mutation: CREATE_PET,
    variables: {
      name: "Optimus",
      owner_id: 1,
      specie: "MAMMALS",
    },
  });

  expect(res).toMatchSnapshot();
});

test("update user", async () => {
  const serverTest = server();
  const { mutate } = createTestClient(serverTest);

  const res = await mutate({
    mutation: UPDATE_USER,
    variables: {
      id: 1,
      name: "wilson",
    },
  });

  expect(res).toMatchSnapshot();
});

test("delete user", async () => {
  const serverTest = server();
  const { mutate } = createTestClient(serverTest);

  const res = await mutate({
    mutation: DELETE_USER,
    variables: {
      id: 2,
    },
  });

  expect(res).toMatchSnapshot();
});

마지막으로, 이것은 우리가 처음으로 테스트를 집행하는 절차이다
1) 사선 운행 테스트: 이동: 위로 표 생성
2) 방사선 운행 테스트: 데이터베이스에 있는 데이터로 피드 데이터베이스 채우기
3) 방사선 운행 테스트: 우리의 테스트를 실행하기 위해 집적
지금 그것을 두 번째로 운행하려면 우리는 운행해야 한다
1) 방사선 운행 테스트: 씨앗db
2) 사선 운행 테스트: 통합
너는 이런 출력을 얻을 수 있을 것이다

읽어주셔서 감사합니다.😉, 어떤 의문, 건의, 정정도 아래의 평론에서 저에게 알려주십시오😊

좋은 웹페이지 즐겨찾기