Introduction to Angular Test- Driven Development
| Unit/e2e Testing Guides
ü What
is Unit Test in Angular?
ü What
Is Integration Testing in Angular?
ü How
to Test a components inputs as well as its outputs?
ü How
to Interact with a components view?
Types
of Test in Angular 4/2 and Angular –
The all great developer knows his/her testing tools
uses. Understanding your tools for testing is essential before diving into
writing tests.
The Testing
is depends on your project requirements and the project cost. The types of
Testing looks like -
1. Unit
Test
2. Integration
Test
3. End
to End (e2e) Test
Unit
Test
– What is Unit Test in Angular? The Unit Test is used to testing a single
function, single components in Isolation. This is very fast.
In this Test, we are not able to say that everything
is all right in the application. Just for a single Unit or function assure that
working fine.
Integration
Testing – What Is Integration Testing in Angular? The
Integration Testing is used to testing a component with templates and this testing
containing more time as per comparison Unit Test.
End
to End Test (e2e) – What is End-to-End Testing in Angular? The
End to End Testing is used to testing the entire application looks like -
1. All
User Interactions
2. All
Service Calls
3. Authentication/Authorization
of app
4. Everything
of App
This is the actual testing of your append it is
fast action.
Unit testing and Integrations testing will do as
fake calls but e2e testing is done
with your actual Services and APIs calls.
Recommended Unit Testing Tools – Angular 4/2 and
Angular
· Karma
· Jasmine
and
· QUnit
Test
Function – After installing everything as per your
project requirements, CREATE your project.
The following Steps –
ü ng
new YourTestProject
ü ng
install
ü ng
serve/ng test
Note
– If you are going to development then type ng server command and if you want to test your project, you should
type ng test command. After type ng test command and press inter. It’s taking some time to
installing everything in your project for test.
Test
functions–
1. describe
– Test suit (just a function)
2. it
- The spec or test
3. expect
- Expected outcome.
Triple Rule of Testing –
1. Arrange
- Create and Initialize the Components
2. Act
- Invoke the Methods/Functions of
Components
3. Assert
- Assert the expected outcome/behaviour
Best
Practices - The quick list of best practices.
ü Use
beforeEach() to Initialize the
context for your tests.
ü Make
sure the string descriptions you put in describe
() and it () make sense as output
ü Use
after () and afterEach () to clean-up your tests if there is any state that may
bleed over.
ü If
any one test is over 15 lines of code, you may need to refactor the test
A Simple Example as –
import
{ TestBed, async
} from '@angular/core/testing';
import
{ AppComponent } from
'./app.component';
//describe – Test suit (just a
function)
describe('AppComponent',
() => {
beforeEach(async(()
=> {
TestBed.configureTestingModule({
declarations: [AppComponent]
}).compileComponents();
}));
// it - The spec or
test
it('should
have hello property', function()
{
const fixture
= TestBed.createComponent(AppComponent);
const app
= fixture.debugElement.componentInstance;
//expect – This Is For expected outcome.
expect(app.hello).toBe('Hello,
Anil!');
});
});
Example
1
–
app.component.ts –
import
{ Component } from
'@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export
class AppComponent
{
title = 'app';
}
app.component.spec.ts –
import
{ TestBed, async
} from '@angular/core/testing';
import
{ AppComponent } from
'./app.component';
describe('AppComponent',
() => {
beforeEach(async(()
=> {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the
app', async(()
=> {
const fixture
= TestBed.createComponent(AppComponent);
const app
= fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as
title 'app'`, async(()
=> {
const fixture
= TestBed.createComponent(AppComponent);
const app
= fixture.debugElement.componentInstance;
expect(app.title).toEqual('app');
}));
it('should render
title in a h1 tag', async(()
=> {
const fixture
= TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled
= fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome
to app!');
}));
});
app.component.html –
<div
style="text-align:center">
<h1> Welcome to {{title}}! </h1>
</div>
<h2>Here
are some links to help you start: </h2>
<ul>
<li>
<h2><a
target="_blank"
rel="noopener"
href="https://code-sample.com/">Tour
of Examples</a></h2>
</li>
<li>
<h2><a
target="_blank"
rel="noopener"
href="https://code-sample.com/">CLI
Documentation</a></h2>
</li>
</ul>
Example
2 – Login Testing
login.component.ts-
import
{ Component, OnInit,
EventEmitter,Input,
Output, ViewEncapsulation
} from '@angular/core';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
encapsulation: ViewEncapsulation.None
})
export
class LoginComponent
implements OnInit
{
@Output() loggedIn
= new EventEmitter<User>();
@Input() enabled
= true;
constructor() { }
ngOnInit() { }
login(email,
password) {
if (email
&& password)
{
this.loggedIn.emit(new
User(email,
password));
}
console.log(`Login
${email}
${password}`);
}
}
export
class User
{
constructor(public
email: string,
public password:
string) {
}
}
login.component.spec.ts –
import
{ async, ComponentFixture,
TestBed } from
'@angular/core/testing';
import
{Component, DebugElement}
from "@angular/core";
import
{LoginComponent, User
} from './login.component';
import
{By} from
"@angular/platform-browser";
describe('LoginComponent',
() => {
let component:
LoginComponent;
let fixture:
ComponentFixture<LoginComponent>;
let submitElement:
DebugElement;
let loginElement:
DebugElement;
let passwordElement:
DebugElement;
beforeEach(async(()
=> {
TestBed.configureTestingModule({
declarations: [LoginComponent]
})
.compileComponents();
}));
beforeEach(() =>
{
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
submitElement = fixture.debugElement.query(By.css('button'));
loginElement = fixture.debugElement.query(By.css('input[type=email]'));
passwordElement = fixture.debugElement.query(By.css('input[type=password]'));
});
it('Setting enabled to
false disabled the submit button', () =>
{
component.enabled
= false;
fixture.detectChanges();
//Expected outcome
expect(submitElement.nativeElement.disabled).toBeTruthy();
});
it('Setting enabled to
true enables the submit button', () =>
{
component.enabled
= true;
fixture.detectChanges();
//Expected outcome
expect(submitElement.nativeElement.disabled).toBeFalsy();
});
it('Entering email and
password emits loggedIn event', () =>
{
let user:
User;
loginElement.nativeElement.value
= "anil.singh@code-sample.com";
passwordElement.nativeElement.value
= "$ystem!1356";
// Subscribe to the Observable and store the user
in a local variable.
component.loggedIn.subscribe((value)
=> user
= value);
// This sync emits the event and the subscribe
callback gets executed above
submitElement.triggerEventHandler('click',
null);
//Expected outcome
expect(user.email).toBe("anil.singh@code-sample.com");
expect(user.password).toBe("$ystem!1356");
});
});
login.component.html –
<form>
<label>Email</label>
<input
type="email"
#email>
<label>Password</label>
<input
type="password"
#password>
<button
type="button"
(click)="login(email.value,
password.value)"
[disabled]="!enabled">Login
</button>
</form>