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:
- No arquivo de configuração do karma:
ClientApp/src/karma.conf.js
. - 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' - } } } }); };
- Navegue até a pasta ClientApp:
$ cd ~/ClientApp
- 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).
Exemplos de matchers mais utilizados. O restante se encontra em: Jasmine Matchers
const deuMolinho: boolean = true;
expect(deuMolinho).toBe(true);
const deuMolinho: boolean = true;
expect(deuMolinho).toBeTruthy(true);
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("timesheet.component.ts", () => {
it("should add a new time entry");
it("should fail to add a time entry");
});
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'
}
}
};
});
});
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());
});
});
No final de cada spec, executar uma ação destrutiva
afterEach(() => {
this.cleanup();
});
const cleanup = (): void =>
delete this.mock.employees;
Executado no final de todas as specs
describe("timesheet.component.ts", () => {
afterAll(() => {
this.cleanup();
});
})
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();
});
});
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;
});
});
})
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();
});
})
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();
});
});