Testes com NestJs e Prisma

O NestJs é uma ferramenta incrível que descobri não faz muito tempo. 백엔드에 익숙하지 않은 사용자는 NestJs 및 Prisma에서 테스트할 수 있는 모든 종류의 테스트에 어려움을 겪을 수 있습니다. Por isso, quero compartilhar esse pequeno passo a passo para que você consiga testar suas aplicações mais facilmente.

Pra esse tutorial pularei a parte de instalação e configuração do Nest e do Prisma. Vamos는 API를 que temos uma que precisa acessar um banco de dados SQL e entregar postagens de um blog para o client입니다.


Criando o modulo 게시물



Vamos começar primeiramente criando o nosso modulo chamado posts, rodando o seguinte comando:
nest generate resource posts
Com esse comando o Nest criará automaticamente um modulo CRUD pronto para ser usado. Vamos então criar nossa entidade chamada Post onde será mapeado a tabela da base de dados

import { Prisma } from '@prisma/client';

export class Post implements Prisma.PostUncheckedCreateInput {
  id?: number;
  titulo: string;
  conteudo?: string;
  publicado?: boolean;
  autor: string;

  constructor(partial: Partial<Post>) {
    Object.assign(this, partial);
  }
}


Criando os serviços



아고라, vamos criar a nossa camada de regras de negócio e interação com a base de dados. 더 이상 arquivo posts.service.ts teremos um CRUD básico, com métodos para retornar criar, listar, atualizar e deletar posts do nosso blog.

import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreatePostDto } from './dto/create-post.dto';
import { UpdatePostDto } from './dto/update-post.dto';

@Injectable()
export class PostsService {
  constructor(private readonly prisma: PrismaService) {}

  create(createPostDto: CreatePostDto) {
    return this.prisma.post.create({ data: createPostDto });
  }

  findAll() {
    return this.prisma.post.findMany();
  }

  findOne(id: number) {
    return this.prisma.post.findUnique({ where: { id } });
  }

  async update(id: number, updatePostDto: UpdatePostDto) {
    try {
      return await this.prisma.post.update({
        where: { id },
        data: updatePostDto,
      });
    } catch (error) {
      throw new NotFoundException();
    }
  }

  async remove(id: number) {
    try {
      await this.prisma.post.delete({ where: { id } });
    } catch (error) {
      throw new NotFoundException();
    }
  }
}


클래스 생성자가 아닌 Prisma 서비스를 선언한 기초에 대해 수리하십시오.

Criando nossos testes com o Prisma



광장, 마지막으로 고환이 오십시오. Começando pela camada de serviços, que onde mais devemos ter testes.
Primeiramente precisamos mockar os retornos dos métodos do Prisma. jest.fn().mockReturnValue() 기능이 필요합니다. Podemos fazer da seguinte maneira:

// Criamos primeiro nos dados fícticios para serem retornados do Prisma
const fakePosts = [
  {
    id: 1,
    titulo: 'Primeiro post do blog',
    conteudo: 'Apenas um teste.',
    publicado: true,
    autor: 'João',
  },
  {
    id: 2,
    titulo: 'Testes unitários',
    conteudo: 'Conteúdo sobre testes unitários.',
    publicado: true,
    autor: 'Vitor',
  },
  {
    id: 3,
    titulo: 'Javascript',
    conteudo: 'Conteúdo sobre testes Javascript.',
    publicado: false,
    autor: 'Teste',
  },
];

// E depois nosso objeto de mock do Prisma, retornando os dados falsos
const prismaMock = {
  post: {
    create: jest.fn().mockReturnValue(fakePosts[0]),
    findMany: jest.fn().mockResolvedValue(fakePosts),
    findUnique: jest.fn().mockResolvedValue(fakePosts[0]),
    update: jest.fn().mockResolvedValue(fakePosts[0]),
    delete: jest.fn(), // O método delete não retorna nada
  },
};


Depois de criar os mocks, vamos configurar o testing module do Nest.

describe('PostsService', () => {
  let service: PostsService;
  let prisma: PrismaService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        PostsService,
        { provide: PrismaService, useValue: prismaMock },
      ],
    }).compile();

    service = module.get<PostsService>(PostsService);
    prisma = module.get<PrismaService>(PrismaService);
  });
});


Primeiro는 Prisma 서비스의 변수를 선언합니다. Depois adicionamos um provider mockado do PrismaService e usavamos como valor o mock que criamos anteriormente. E por último inicializamos a variável do serviço e do Prisma.

Logo após a declaração do beforeEach vamos declarar o afterEach para limparmos os mocks apos a execução de cada teste.

  afterEach(() => {
    jest.clearAllMocks();
  });


Agora vamos para o nosso primeiro cenário de testes que vai ser o em cima do método findAll

  describe('findAll', () => {
    it(`should return an array of posts`, async () => {
      const response = await service.findAll();

      expect(response).toEqual(fakePosts);
      expect(prisma.post.findMany).toHaveBeenCalledTimes(1);
      expect(prisma.post.findMany).toHaveBeenCalledWith(/* nothing */);
    });
  });


Não temos nada de difícil aqui. Primeiro nós precisamos chamar nosso método do service e depois criar nossos expects para validar o que for necessário. Prisma através do objeto que criamos no começo para ele (prisma.post.findMany) para esse caso.

findOne 테레모의 시나리오:

  describe('findOne', () => {
    it(`should return a single post`, async () => {
      const response = await service.findOne(1);

      expect(response).toEqual(fakePosts[0]);
      expect(prisma.post.findUnique).toHaveBeenCalledTimes(1);
      expect(prisma.post.findUnique).toHaveBeenCalledWith({
        where: { id: 1 },
      });
    });

    it(`should return nothing when post is not found`, async () => {
      jest.spyOn(prisma.post, 'findUnique').mockResolvedValue(undefined);

      const response = await service.findOne(99);

      expect(response).toBeUndefined();
      expect(prisma.post.findUnique).toHaveBeenCalledTimes(1);
      expect(prisma.post.findUnique).toHaveBeenCalledWith({
        where: { id: 99 },
      });
    });
  });


Jest에서 스파이 기능을 사용할 수 있도록 수리하십시오. Precisamos usar ela para sobrepor o mock que criamos no começo, pois para esse caso estamos testando se o serviço retorna undefined quando não é encontrado nenhuma postagem com um determinado id. Então, com o spyOn podemos mockar que o retorno do método findUnique será undefined.

Para o resto dos métodos teremos os mesmos conceitos:

  describe('create', () => {
    it(`should create a new post`, async () => {
      const response = await service.create(fakePosts[0]);

      expect(response).toBe(fakePosts[0]);
      expect(prisma.post.create).toHaveBeenCalledTimes(1);
      expect(prisma.post.create).toHaveBeenCalledWith({
        data: fakePosts[0],
      });
    });
  });

  describe('updateOne', () => {
    it(`should update a post`, async () => {
      const response = await service.update(1, fakePosts[0]);

      expect(response).toEqual(fakePosts[0]);
      expect(prisma.post.update).toHaveBeenCalledTimes(1);
      expect(prisma.post.update).toHaveBeenCalledWith({
        where: { id: 1 },
        data: fakePosts[0],
      });
    });

    it(`should return NotFoundException when no post is found`, async () => {
      const unexistingPost = {
        id: 42,
        titulo: 'teste',
        conteudo: 'Conteudo Teste',
        publicado: false,
        autor: 'Teste',
      };

      jest.spyOn(prisma.post, 'update').mockRejectedValue(new Error());

      try {
        await service.update(42, unexistingPost);
      } catch (error) {
        expect(error).toEqual(new NotFoundException());
      }

      expect(prisma.post.update).toHaveBeenCalledWith({
        where: { id: 42 },
        data: unexistingPost,
      });
    });
  });

  describe('deleteOne', () => {
    it(`should delete post and return empty body`, async () => {
      expect(await service.remove(1)).toBeUndefined();
      expect(prisma.post.delete).toHaveBeenCalledTimes(1);
      expect(prisma.post.delete).toHaveBeenCalledWith({ where: { id: 1 } });
    });

    it(`should return NotFoundException if post does not exist`, async () => {
      jest.spyOn(prisma.post, 'delete').mockRejectedValue(new Error());

      try {
        await service.remove(99);
      } catch (error) {
        expect(error).toEqual(new NotFoundException());
      }

      expect(prisma.post.delete).toHaveBeenCalledTimes(1);
      expect(prisma.post.delete).toHaveBeenCalledWith({
        where: { id: 99 },
      });
    });
  });


결론



Espero que tenham gostado desse pequeno tutorial sobre testes com Nest e Prisma, não cobre tudo mas é um bom ponto de partida para criar os primeiros testes com essas ferramentas.
Não passei muito pelo controller e outras seções do modulo do Nest, mas podemos utilizar o controller que o Nest gera automaticamente com a CLI. Você pode conferir no meu repositório do GitHub como fazer os testes para o controller (é bem simples).

저장소 링크: https://github.com/mrtins/nest-blog-posts

좋은 웹페이지 즐겨찾기