ng new app01
cd app01
A teszt futtatása:
ng test
===== Jasmine =====
==== Fontosabb Jasmine eszközök ====
A Jasmine teszteket a describe() függvény paramétereként írjuk.
Egy teszt egy it() függvény paraméterében van leírva.
A tesztek írást segítik a beforeEach, afterEach, beforeAll, afterAll horgok.
* describe - Egy blokk definiálása
* Minden egyedi tesztet egy ilyen blokkba kerül.
* Egyedi teszt, angolul individual test, röviden it.
* beforeEach
* Minden egyes teszt előtt lefut.
* Ha 5 teszt van 5-ször fut le.
* A teszt beállításait tartalmazza.
* afterEach
* Minden egyes teszt után lefut.
* Leépítési funkciók.
* beforeAll
* Az összes teszt előtt egyszer fut le.
* afterAll
* Az összes teszt után egyszer fut le.
* it
* Egy teszteset leírása
A tesztekben figyelmeztetéseket generálunk az elvárt értékek és viselkedések alapján.
Ha nem az elvárt értéket vagy viselkedést kapjuk figyelmeztetést küldünk. A
figyelmeztetéseket az expect() függvénnyel vezetjük be, amin futtatunk egy konkrét
figyelmeztetést.
Figyelmeztetések, illesztések:
* toBeDefined - van ilyen érték meghatározva?
* toBeTruthy - egy érték igaz?
* toContain - a karakterlánc vagy tömb tartalmaz egy elemet?
* toEqual - két érték egyenlő?
* toThrow- dob valamit egy függvény? *
* toBeNull - az érték null
* toBe - primitív típusoknál mint a toEqual; egyébként: két objektum megegyezik?
* toBeFalsy - az érték hamis?
A következő példában azt várom, hogy a **myData** változó értéke nagyobb mint 4:
expect(myData).toBeGreaterThan(4);
Az állítás megfordítása egy not taggal:
expect(myData).not.toBeGreaterThan(4);
Készíthetünk saját illeszkedést is.
Az összes egyezés:
* https://jasmine.github.io/api/edge/matchers.html
==== TestBed ====
A TestBed **Angular** teszteléshez elérhető eszköz. ((Ha Angular nélkül használjuk a Jasmin keretrendszert, a TestBed nem áll rendelkezésre.))
import { TestBed } from '@angular/core/testing';
==== By ====
A By segítségével elérhetők a HTML oldal elemei.
import { By } from '@angular/platform-browser';
===== Beállítás =====
Az újabb Angular verziók ng parancsa nem hozza létre a
**karma.conf.js** állományt, a beállítások memóriában vannak.
Ha saját konfigurációt szeretnénk, a konfigurációs fájl létrehozása
és bejegyzése:
ng generate config karma
Az nem elég, ha létrehozzuk és írunk bele. Szükség van egy bejegyzésre
az angular.json konfigurációs fájlban.
==== Hasznos beállítások ====
A tesztek véletlenszerűen vagy sorrendbe fussanak:
client: {
jasmine: {
random: false
},
},
Milyen böngészőben fusson:
browsers: ['Chromium'],
A Chorome böngésző úgy veszi, hogy még sosem volt elindítva,
ezért mindig megkérdezi, hogy milyen keresőt választunk.
Ebből a szempontból jobb a Chromium.
==== Lásd még ====
* https://angular.dev/guide/testing
* https://jasmine.github.io/api/edge/Configuration.html
* https://karma-runner.github.io/6.4/config/browsers.html
===== Kezdeti teszt =====
Ha kapcsolók nélkül létrehozunk egy projektet az app.component számára létre jön egy alapértelmezett
teszt is.
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'app08'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('app08');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('app08 app is running!');
});
});
===== Kiegészítve =====
Kezdetnek tegyünk egy beforeAll() függvényt a tesztek elejére.
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeAll(()=>{
console.log('Egyszer lefut')
})
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'app08'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('app08');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('app08 app is running!');
});
});
===== Teszt indítása =====
ng test
A tesztek alapértelmezetten véletlenszerű sorrendben hajtódnak végre.
A teszt egy új böngészőablakban fut, és az eredményt is látjuk.
===== Teszt kiegészítése =====
Írjunk egy metódust az app.component.ts fájlban:
calcArea(base: number, height: number) {
return (base * height) / 2;
}
Egy negyedik tesztet adunk a meglévő tesztekhez:
describe('AppComponent', () => {
//...
it('Háromszög tesztelése', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.calcArea(30, 35)).toEqual(525);
})
}
===== Kiegészítő osztályhoz tesztírás =====
Ha készítünk egy triangle.ts fájlt a Triangle osztály számára, készíthetünk hozzá
tesztállományokat is. Követelmény a .spec.ts kiterjesztés.
export class Triangle {
base: number;
height: number;
area: number;
constructor() {
this.base = 0;
this.height = 0;
this.area = 0;
}
calcArea() {
this.area = this.base * this.height / 2;
}
}
import { Triangle } from './triangle';
describe('Triangle osztály tesztje', () => {
let triangle: Triangle;
beforeEach(() => {
triangle = new Triangle();
});
it('Területszámítás', () => {
triangle.base = 30;
triangle.height = 35;
triangle.calcArea();
let actual = triangle.area;
let expected = 525;
expect(expected).toEqual(actual);
});
});
===== Futó alkalmazás =====
Az alapértelmezetten létrejött utolsó, "should render title" nevű teszt megkövetel egy HTML tartalmat:
{{ title }} app is running!
Az app/app.component.html fájlt tartalmát törölni szoktuk, mivel saját tartalommal töltjük azt meg.
A "should render title" teszt ezért hibára fut.
===== FormsModule =====
Ha az **app.module.ts** fájlban importáljuk a **FormsModule** modult,
és input elemeket hozunk létre az **app.component.html**
fájlban akkor az importálást a tesztfájlban is meg kell
csinálni:
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [
FormsModule
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'triangle'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('triangle');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('triangle app is running!');
});
});
A HttpClient teszthez:
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TasksComponent ],
imports: [HttpClientModule]
})
.compileComponents();
});
===== HTML elemek tesztje =====
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { By } from '@angular/platform-browser';
describe('AppComponent', () => {
it('létrehozható az app objektum', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it('van nav elem', () => {
const fixture = TestBed.createComponent(AppComponent);
const nav = fixture.debugElement.queryAll(By.css('nav'));
expect(nav.length).toBe(1);
});
it('van nav elemben két div elem', () => {
const fixture = TestBed.createComponent(AppComponent);
const nav_div = fixture.debugElement.queryAll(By.css('nav div'))
expect(nav_div.length).toBe(2);
});
});
==== Osztály vizsgálata ====
it('a nav elemnek van navbar osztálya', () => {
const fixture = TestBed.createComponent(AppComponent);
const navbar = fixture.debugElement.queryAll(By.css('.navbar'));
expect(navbar.length).toBe(1);
});
==== Tartalom ====
A **query()** függvény egyetlen elemmel tér vissza.
A **queryAll()** függvény az összes elemmel tér vissza, tömbként.
it('második elem tartalma', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const aElem = fixture.debugElement.queryAll(By.css('.nav-item'));
expect(aElem[1].nativeElement.textContent.trim()).toBe('Features');
});
===== HttpClien tesztje =====
Legyen a példa kedvért egy ApiService osztály, ami HttpClientModule-t
igényli. A kezdeti tesztfájl így néz ki:
import { TestBed } from '@angular/core/testing';
import { ApiService } from './api.service';
describe('ApiService', () => {
let service: ApiService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ApiService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
A HttpClienModule-t külön be kell itt is tölteni.
import { HttpClientModule } from '@angular/common/http';
import { TestBed } from '@angular/core/testing';
import { ApiService } from './api.service';
describe('ApiService', () => {
let service: ApiService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
]
});
service = TestBed.inject(ApiService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
===== Függelék =====
==== Példa ====
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { By } from '@angular/platform-browser';
describe('AppComponent', () => {
let fixture : ComponentFixture;
let app: AppComponent;
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
app = fixture.componentInstance;
});
it('létrehozható az app objektum', () => {
expect(app).toBeTruthy();
});
it('van nav elem', () => {
const nav = fixture.debugElement.queryAll(By.css('nav'));
expect(nav.length).toBe(1);
});
it('van nav elemben két div elem', () => {
const nav_div = fixture.debugElement.queryAll(By.css('nav div'))
expect(nav_div.length).toBe(2);
});
it('a nav elemnek van navbar osztálya', () => {
const navbar = fixture.debugElement.queryAll(By.css('.navbar'));
expect(navbar.length).toBe(1);
});
it('második elem tartalma', () => {
fixture.detectChanges();
const aElem = fixture.debugElement.queryAll(By.css('.nav-item'));
expect(aElem[1].nativeElement.textContent.trim()).toBe('Valami');
});
});
===== Gyermek komponens =====
Angular gyermek komponens tesztje:
it('app-vehicle meg van', () => {
fixture.detectChanges();
const childElem = fixture.debugElement.queryAll(By.css('app-vehicles'));
expect(childElem).toBeTruthy();
});
===== Linkek =====
* https://angular.io/guide/testing-components-basics (2022)
* https://angular.io/guide/testing-services (2022)
* https://testing-angular.com/ (2022)