Create API with NestJS with TDD approach part one
joedev090

joedev090 @joedev090

About: A enthusiastac software developer with more experience in the frontend side. Fanatic to create a clean code and the best practices of web/mobile technology prefered angular, react.

Location:
Quito, Ecuador
Joined:
Apr 18, 2021

Create API with NestJS with TDD approach part one

Publish Date: Jul 28
0 0

Hey Coders!!!

A lot of time ago, here we have a new article with an incredible approach from testing.

Let's begin!!

What is Testing?

Testing is a crucial part of the software development process that ensures your code works as intended. It helps catch bugs early, reduces development costs, and improves software quality. There are two main types of testing:

Manual Testing: This involves manually executing test cases without the use of automation tools. It can be time-consuming and is often used for exploratory testing.

Automated Testing: This involves writing scripts or using tools to automatically execute tests. Automated tests can be run frequently and consistently, making them ideal for regression testing.

The next step is introducing to Unit Testing.

What is Unit Testing??

Unit testing is a level of software testing where individual components of a software are tested.

The purpose is to validate that each unit of the software performs as designed. A unit is the smallest testable part of any software. It usually has one or a few inputs and usually a single output.

And now the best part...

You will know how powerful is this concept and I can say this way of programming!!

Introduction to TDD

Test-Driven Development (TDD) is a software development process that relies on the repetition of a very short development cycle.

The cycle involves writing a test for a new function before writing the function itself.

The goal of TDD is to write clean code that works, and it achieves this by ensuring that the code is thoroughly tested.

The TDD Cycle

The TDD cycle can be described as follows:

  1. Write a Failing Test: Start by writing a test for a small piece of functionality that you want to implement. This test should fail initially because the functionality isn't implemented yet.

  2. Write Minimal Code to Pass the Test: Write the minimal amount of code necessary to make the test pass. The goal here is not to write perfect code but to get the test to pass.

  3. Refactor the Code: Once the test is passing, refactor the code to improve its structure and readability. Ensure that the tests still pass after refactoring.

This cycle is often referred to as

"Red-Green-Refactor":

Red: The test fails.
Green: The test passes.
Refactor: Improve the code without breaking the tests.

I know that the theory sometimes is boring, but it is necessary to have the conext of our next project!!

Let's begin with the practice....

Creating a Web API crud with Nestjs using TDD way.

  • Install NestJS(mandatory have installed latest version of nodejs)

npm install -g @nestjs/cli

  • Create a new Nestjs project
nest new properties-api
cd properties-api

Enter fullscreen mode Exit fullscreen mode
  • Then we will install the dependencies for TypeORM and SQLite

npm install @nestjs/typeorm typeorm sqlite3

  • The next step is configured TypeORM in your app.module.ts file to use SQLite
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'sqlite',
      database: 'db.sqlite',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true,
    }),
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode
  • Then use the Nest CLI to generate a module, service, and controller for managing properties.
nest generate module properties
nest generate service properties
nest generate controller properties

Enter fullscreen mode Exit fullscreen mode

Go ahead, the important part is beginning!!

  • Create the property entity in properties/entities/property.entity.ts
// src/properties/entities/property.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Property {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  description: string;

  @Column()
  location: string;

  @Column()
  imageUrl: string;

  @Column()
  unitsAvailable: number;

  @Column({ default: false })
  hasWifi: boolean;

  @Column({ default: false })
  hasLaundry: boolean;
}

Enter fullscreen mode Exit fullscreen mode
  • In this case, I will create a test folder for the Test file of the service.

You can do it with these lines in your terminal.

mkdir -p src/properties/__test__
touch src/properties/__test__/properties.service.spec.ts
Enter fullscreen mode Exit fullscreen mode

And the magin begins now!!

Let's write a failing Test for findAll in
src/properties/test/properties.service.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { PropertiesService } from '../properties.service';
import { Property } from '../entities/property.entity';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

describe('PropertiesService', () => {
  let service: PropertiesService;
  let repository: Repository<Property>;

  beforeEach(async () => {
    const mockRepository = {
      find: jest.fn().mockResolvedValue([]),
    };

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        PropertiesService,
        {
          provide: getRepositoryToken(Property),
          useValue: mockRepository,
        },
      ],
    }).compile();

    service = module.get<PropertiesService>(PropertiesService);
    repository = module.get<Repository<Property>>(getRepositoryToken(Property));
  });

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

  describe('findAll', () => {
    it('should return an array of properties', async () => {
      const result = await service.findAll();
      expect(result).toEqual([]);
    });
  });
});

Enter fullscreen mode Exit fullscreen mode

We are creating firstly the test before create the findAll function in the service and then run

npm run test
Enter fullscreen mode Exit fullscreen mode

This test will fail, and the reason is because we need to create the function in the service.

  • So Implement the findAll Method in the Service:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Property } from './entities/property.entity';

@Injectable()
export class PropertiesService {
  constructor(
    @InjectRepository(Property)
    private propertiesRepository: Repository<Property>,
  ) {}

  findAll(): Promise<Property[]> {
    return this.propertiesRepository.find();
  }
}
Enter fullscreen mode Exit fullscreen mode

This is the way we should do using TDD.
First we implement a basic using testing case and then we implement the function or the functionality!!!

  • Let's repeat the process for the Property controller

Create the test file

touch src/properties/__test__/properties.controller.spec.ts

  • Write a failing testing for the controller
import { Test, TestingModule } from '@nestjs/testing';
import { PropertiesController } from '../properties.controller';
import { PropertiesService } from '../properties.service';

describe('PropertiesController', () => {
  let controller: PropertiesController;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [PropertiesController],
      providers: [
        {
          provide: PropertiesService,
          useValue: {
            findAll: jest.fn().mockResolvedValue([]),
          },
        },
      ],
    }).compile();

    controller = module.get<PropertiesController>(PropertiesController);
  });

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

  describe('findAll', () => {
    it('should return an array of properties', async () => {
      const result = await controller.findAll();
      expect(result).toEqual([]);
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

Then execute:

npm run test

It will fail!!

And then, we implement the controller function in src/properties/properties.controller.ts

import { Controller, Get } from '@nestjs/common';
import { PropertiesService } from './properties.service';
import { Property } from './entities/property.entity';

@Controller('properties')
export class PropertiesController {
  constructor(private readonly propertiesService: PropertiesService) {}

  @Get()
  findAll(): Promise<Property[]> {
    return this.propertiesService.findAll();
  }
}
Enter fullscreen mode Exit fullscreen mode

After these steps we can repeat the testing with

npm run test

It should pass all tests

And be sure to have the properties.module.ts with this code:

import { Module } from '@nestjs/common';
import { PropertiesService } from './properties.service';
import { PropertiesController } from './properties.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Property } from './entities/property.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Property])],
  providers: [PropertiesService],
  controllers: [PropertiesController]
})
export class PropertiesModule {}

Enter fullscreen mode Exit fullscreen mode

Finally start your nestJs Application

npm run start

And there you go....

The first part of our NestJs app using TDD.

You can test this project with Postman or in your browser.

http://localhost:3000/properties

You can see an empty [] array!!

Keep in touch to see the next part of this project, I will add the github repository where you can see the entire code I explained.

Let me know if you have any suggestions or questions, please!!

Keep coding! :)

https://github.com/joeaspiazudeveloper/nestjs-houselocation-tdd

Comments 0 total

    Add comment