Skip to content

Latest commit

 

History

History
364 lines (282 loc) · 9.7 KB

unit-tests.org

File metadata and controls

364 lines (282 loc) · 9.7 KB

Karma & Jasmine

Configuração

Setup necessário antes de rodar os testes.

O karma-parallel é um plugin do Karma que acelera a execução dos testes através da invocação de múltiplas instâncias de um navegador, decidindo qual bloco describe deve rodar em tal determinado navegador.

Antes de executar os testes, removemos as seções no arquivo de configuração do karma que configuram o karma-parallel, visto que só precisamos de um navegador – e queremos economizar memória:

  1. No arquivo de configuração do karma: ClientApp/src/karma.conf.js.
  2. Removemos as seguintes seções:
    module.exports = function(config) {
      config.set({
        // NOTE: 'parallel' must be the first framework in the list
    -    frameworks: ['mocha' /* or 'jasmine' */],
    +    frameworks: ['parallel', 'mocha' /* or 'jasmine' */],
        plugins: [
    -        require('karma-parallel'),
            ...
        ],
    -    parallelOptions: {
    -         executors: 4, // Defaults to cpu-count - 1
    -         shardStrategy: 'round-robin'
    -      }
          }
        }
      });
    };
        

Executando os testes

  1. Navegue até a pasta ClientApp: $ cd ~/ClientApp
  2. Execute os testes: $ ng tests --code-coverage

    A flag --code-coverage é usada para gerar um relatório de cobertura – a porcentagem de linhas executadas pelos testes (line coverage) e garantir que cada uma das ramificações possíveis de cada ponto de decisão seja executada pelo menos uma vez (branch coverage).

Jasmine

Matchers

Exemplos de matchers mais utilizados. O restante se encontra em: Jasmine Matchers

toBe

const deuMolinho: boolean = true;

expect(deuMolinho).toBe(true);

ToBeTruthy/ToBeFalsy

const deuMolinho: boolean = true;

expect(deuMolinho).toBeTruthy(true);

Métodos Globais

it(description: string, fn: callback, timeout: int)

it('should sum 1 and 2', () => {
  const sum: number = 1 + 2;

  expect(sum).toBe(3);    // ===
  expect(sum).toEqual(3); // ==

  expect(sum == 3).toBe(true);

  expect(sum).toBeGreaterThan(1);
  expect(sum).toBeGreaterThanOrEqual(2);
  expect(sum).toBeLessThan(4);
  expect(sum).toBeDefined();
  expect(sum).toBeInstanceOf(number);
});

describe(description: string)

describe("timesheet.component.ts", () => {
  it("should add a new time entry");
  it("should fail to add a time entry");
});

Setup

beforeAll(fn: callback, timeout: int)

Executa antes de todos os specs dentro de um describe

describe("timesheet.component.ts", () => {
  let mock: any;

  beforeAll(() => {
    this.mock = {
      employees: {
        employee: {
          id: 1,
          name: 'Bruno'
        },
        employee: {
          id: 2,
          name: 'Eduardo'
        }
      }
    };
  });
});
beforeEach(fn: callback, timeout: int)

Executa para cada spec dentro de um describe

describe("timesheet.component.ts", () => {
  let mock: any;

  afterEach(() => {
    this.mock
      .employees
      .map(employee => employee.updatedOn = new Date());
  });
});

Teardown

afterEach(fn: callback, timeout: int)

No final de cada spec, executar uma ação destrutiva

afterEach(() => {
  this.cleanup();
});

const cleanup = (): void =>
  delete this.mock.employees;
afterAll(fn: callback, timeout: int)

Executado no final de todas as specs

describe("timesheet.component.ts", () => {
  afterAll(() => {
    this.cleanup();
  });
})

SpyOn

Observa o retorno de um método de um objeto

class Math {
  constructor() { }

  increment(num: number): number {
    return ++num;
  }
}

describe("timesheet.component.spec.ts", () => {
  const math: Math;

  beforeAll(() => {
    this.math = new Math();
  })

  it('should increment by one', () => {
    const num: number = 4;

    let spy = spyOn(math, 'increment')
      .withArgs(num)
      .and
      .returnValue(5);

    math.increment(num);

    expect(spy).toHaveBeenCalled();
  });
});

Testes

Component

Setup

import {
  TestBed,
  ComponentFixture
} from '@angular/core/testing';

describe("timesheet.component.ts", () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [
        TimesheetComponent
      ],
      imports: [
        BrowserModule,
      ]
    }).compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(TimesheetComponent);
        component = fixture.componentInstance;
      });
  });
})

Testar métodos

import {
  TestBed,
  ComponentFixture
} from '@angular/core/testing';

describe("timesheet.component.ts", () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [
        TimesheetComponent
      ],
      imports: [
        BrowserModule,
      ]
    }).compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(TimesheetComponent);
        component = fixture.componentInstance;
      });
  });

  it('should create the component', () => {
    component.ngOnInit();
  });

  it('should fetch all employees', () => {
    const spy = spyOn(component, 'getEmployees')
      .and
      .returnValue(Promise.resolve(this.mock.employees));

    component.getEmployees();

    expect(spy).toHaveBeenCalled();
  });

  it('should fail to fetch all employees', () => {
    const spy = spyOn(component, 'getEmployees')
      .and
      .returnValue(Promise.reject({}));

    component.getEmployees();

    expect(spy).toHaveBeenCalled();
  })

  it('should get employee by Id', () => {
    const id: number = 1;

    const employee: object = this.mock.employees.find(f => f.id == id);

    const spy = spyOn(component, 'getEmployees')
      .withArgs(id)
      .returnValue(employee);

    component.getEmployee(id);

    expect(employee).not.toBeNull();
    expect(spy).toHaveBeenCalled();
  });
})

Service

import { ApplicationSettingsService } from 'app/shared/application-settings/configuration.service';
import { HttpModule } from '@angular/http';
import { TimesheetService } from '../timesheet.service';

describe("timesheet.service.ts", () => {
  const mock: any = {};

  configureTestSuite(() => {
    TestBed.configureTestingModule({
      providers: [
        TimesheetService,
        OAuthService,
        UrlHelperService,
        OAuthLogger,
        OAuthService,
        { provide: FUSE_CONFIG, useValue: {} },
        { provide: APP_BASE_HREF, useValue: '/' },
        { provide: ApplicationSettingsService, useClass: ApplicationSettingsServiceScenarioTest }
      ],
      imports: [
        HttpClientTestingModule,
        HttpModule,
        BrowserAnimationsModule,
        NoopAnimationsModule,
        RouterModule.forRoot([]),
      ],
    });

    injector = getTestBed();
    service = injector.get(TimesheetService);
    httpMock = injector.get(HttpTestingController);

    mock.error = {
      message: 'Invalida request parameters',
      response: {
        stautus: 404,
        statusText: 'Bad Request'
      }
    }
  });

  it('should get holidays', async () => {
    const promise = service.getHolidays(mock);
    const req = httpMock
      .expectOne(req => req.method === 'GET' && req.url === service.baseUrl)

    req.flush(dummy);

    expect(await promise).toBeDefined();
  });

  it('should fail to get holidays', async () => {
    const promise = service.getHolidays(mock)
      .catch(error => expect(error).toBeDefined());

    const req = httpMock
      .expectOne(req => req.method === 'GET' && req.url === service.baseUrl)

    req.flush(mock.error.message, mock.error.response);

    expect(await promise).toBeDefined();
  });
});