evheniy / automock

A library for testing classes with auto mocking capabilities using jest-mock-extended

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ISC license npm version Codecov Coverage ci


Logo

AutoMock

Standalone Library for Dependencies Auto Mocking/Stubbing (for TypeScript)

Create solitary unit tests easily, with total isolation of other class dependencies

Installation

Note: sinon is coming soon

With NPM:

npm i -D @automock/jest

Or with Yarn:

yarn add -D @automock/jest

Who can use this library? 🀩

TL;DR

If you use any kind of framework that supports dependency inversion (with any DI engine) like in the following example:

export class AwesomeClass {
  public constructor(private readonly logger: Logger) {}
}

You can use AutoMock.

Tell Me More πŸ€”

Unit testing is actually significant part of our code, and unit tests need to be written quickly and rapidly. Unit tests should be written with complete isolation, which means all the external (injected) dependencies should be mocked (actually, stubbed).

AutoMock does that for you; using simple reflection (which requires a decorator on the class) AutoMock will replace the dependencies with mocks (in this case, jest.fn()), which can also take implementation, see the example in the next section.

Example and Usage πŸ’β€

import { MockOf, Spec } from '@automock/jest';

describe('SomeService Unit Test', () => {
  let someService: MainService;

  let logger: MockOf<Logger>;
  let userService: MockOf<UserService>;

  const USERS_DATA = [{ name: 'user', email: 'user@user.com' }];

  beforeAll(() => {
    const { unit, unitRef } = Spec.createUnit(MainService)
      .mock(FeatureFlagService)
      .using({ isFeatureOn: () => Promise.resolve(true) })
      .compile();

    someService = unit;
    userService = unitRef.get(UserService);
  });

  describe('When something happens', () => {
    beforeAll(() => (userService.getUsers.mockResolvedValueOnce(USERS_DATA));
    
    test('then check something', async () => {
      await service.doSomethingNice();
      expect(logger.log).toHaveBeenCalledWith(USERS_DATA);
    });
  });
});
πŸ“„ Show me the source

@Reflectable()
export class SomeService {
  public constructor(
    private readonly logger: Logger,
    private readonly catsService: CatsService,
    private readonly userService: UserService,
    private readonly featureFlagService: FeatureFlagService,
  ) {}
  
  public async doSomethingNice() {
    if (this.featureFlagService.isFeatureOn()) {
      const users = await this.userService.getUsers('https://example.com/json.json');
      this.logger.log(users);

      return users;
    }
    
    return null;
  }
}


What is this @Reflectable() decorator?

In order to reflect the constructor class params it needs to be decorated with any class decorator, no matter what its original functionality. If you are not using any kind of decorator, you can just use the default decorator that does, literally, nothing; his purpose is to emit class metadata; so no w

But, for example, if you do use @Injecatable() (NestJS or Angular), @Service() (TypeDI), @Component() or any kind of decorator, you don't need to decorate your class with the @Reflectable() decorator.

Still need further example? Jump to full sample πŸ“„

License πŸ“œ

Distributed under the MIT License. See LICENSE for more information.

Acknowledgements πŸ“™

jest-mock-extended

About

A library for testing classes with auto mocking capabilities using jest-mock-extended

License:MIT License


Languages

Language:TypeScript 98.6%Language:JavaScript 1.4%