e2e Tests for API –

Saving Nerves and Hours

https://github.com/valentinkononov

http://kononov.space/

 

@ValentinKononov

 

Developer, Speaker

 

Straight to the point

  • What do we mean by API Testing?
  • Test Data flow / DB Queries
  • Test input/output data transform
  • Test CRUD operations
  • Test REST Endpoints
  • Test Authentication
  • What is Usual approach to test this?

Integration Tests

  • Test the whole module
  • Test Service
  • Mock dependencies
  • Update Mock dependencies
  • Update Mock dependencies
  • Update Mock dependencies

Test REST API

  • Mock Authentication
  • Mock Database / Data Repository
  • Mock all functions returning data
jest.mock('../../../api/src/user/user.service', () => ({...}));
jest.mock('../../../api/src/color/color.service', () => ({...}));
jest.mock('../../../api/src/record/record.service', () => ({...}));
jest.mock('../../../api/src/track/track.service', () => ({...}));
...

Change function -> new output / arguments

-> fix test

const updateSpy = jest.spyOn(projectService, 'update')
	.mockImplementation(async () => expectedResult as unknown as ProjectDto);

Is there alternative?

based on NestJS framework

// step #1 - initialize API

let app: INestApplication;
beforeAll(async () => {
    const moduleRef = await Test.createTestingModule({
        imports: [AppModule],
    })
        .overrideGuard(AuthGuard)
        .useClass(AuthGuardMock)
        .compile();

    app = moduleRef.createNestApplication();
    await app.init();
});

afterAll(async () => {
    await app.close();
});

e2e Tests for API

based on NestJS framework

// step #2 - mock authentication

class AuthGuardMock implements CanActivate {
    canActivate(context: ExecutionContext): boolean {
        const request = context.switchToHttp().getRequest();
        request.user = testUsers[0];
        return true;
    }
}

e2e Tests for API

based on NestJS framework

// step #3 - call API and test

await request(app.getHttpServer())
	.post(`/projects/${testProject.id}/tasks`)
	.send({
		details: 'test task text',
		userId: testId,
		dueDate: testDueDate,
	})
	.expect(201);

e2e Tests for API

based on NestJS framework

// step #4 - verify data

await request(app.getHttpServer())
        .get(`/project/${testProject.id}`)
        .send()
        .expect(200)
        .expect((res: Response) => {
            const data: ProjectDto = res.body;

            expect(data.id).toBe(testProject.id);
            ...
        });

e2e Tests for API

Pros

  • Easy to fix / no need to fix tests
  • Easy to modify
  • Test the whole workflow
  • The minimal amount of mocks
  • Usually tests are very readable

Cons

  • Can take time to write data creation code
  • Takes time to run tests (API initialization)
  • Need to prepare a minimal database (including one for CI server)
Date.now = (): number => {
        return 1635792963551;
    };

Special trick

const mockGlobalDate = (): Date => {
    const dateMock = new Date(1635792963551);

    global.Date = class DateMock extends Date {
        constructor(...args: any[]) {
            if (args.length) {
                // @ts-ignore
                super(...args);
            } else {
                super(dateMock.getTime());
            }
        }
    } as any;

    Date.now = (): number => {
        return dateMock.getTime();
    };
};

@ValentinKononov

@ValentinKononov

Conclusion

  • Make coding easier - add tests
  • e2e tests make changes faster
  • e2e tests cover the whole flow
  • less mocks
  • more happiness
Made with Slides.com