SlideShare una empresa de Scribd logo
1 de 71
Angular Unit Testing
DO I REALLY NEED TO DO IT ?
Alessandro Giorgetti
www.primordialcode.com
GitHub
https://github.com/AGiorgetti/
AngularUnitTestingShowcase
Do I really have to do it?
Short answer:
Are you serious ?!
We just HATE deliver bad / malfunctioning code!
But we need to choose wisely what to test!
It’s like a war!
The operating scenario: «Angular Application».
•Composition of components and services (lots of moving parts).
•Interactions between components and services.
•Interactions between users and the application.
Best of all:
•Most of these Interactions are ASYNC!
We cannot face the fight alone!
We need some help:
•Take advantage of Unit Testing Frameworks, Tools & Utilities
•Surround the System Under Test with Test Doubles.
•Instrument the function calls and/or replace object behavior with something faked for testing
purposes.
•Deal with Asynchronous testing code.
Definition: Unit Testing
The definition is actually pretty vague!
We can define them by the signature points:
•Unit Tests focus on testing small parts (units) of the software system.
•Unit Tests are expected to verify few targetted assertions.
•Unit Tests are expected to be fast.
Definition: Test Double
Objects or Procedures that look and behave like their release-intended counterparts, but are
actually simplified versions that reduce the complexity and facilitate testing.
Like the Stunt-Doubles used in the film-making industry.
Several Types of Test Doubles
•Dummy objects are passed around but never actually used. Usually they are just used to fill
parameter lists.
•Fake objects actually have working implementations, but usually take some shortcut which makes
them not suitable for production (an InMemoryTestDatabase is a good example).
•Stubs provide canned answers to calls made during the test, usually not responding at all to anything
outside what's programmed in for the test.
•Spies are stubs that also record some information based on how they were called. One form of this
might be an email service that records how many messages it was sent.
•Mocks are pre-programmed with expectations which form a specification of the calls they are
expected to receive. They can throw an exception if they receive a call they don't expect and are
checked during verification to ensure they got all the calls they were expecting.
Source: martinfowler.com - https://martinfowler.com/bliki/TestDouble.html
The question is:
How to do Unit Tests in
Angular ?
Testing Frameworks
JASMINE / KARMA
PROTRACTOR
Jasmine / Karma / Protractor
Jasmine is a behavior driven test framework, it can be used to test components, services and even
DOM elements.
http://jasmine.github.io/
Karma is a test runner that was designed to run low level Unit Tests (those that involve single
components, directives and services).
https://karma-runner.github.io
Protractor is an end to end test framework that runs tests against the real application running in a
real instance of the browser (without component mocking).
http://www.protractortest.org/
Preparing the battlefield
Setting up all these frameworks is outside the scope of this talk.
1. We can setup everything from scratch.
2. We can use seeding projects / startup projects with preconfigured environment.
3. Use the consolidated Angular CLI to generate the preconfigured project for us.
Let’s go with option 3, we can fine tune some configurations options later!
Karma / Jasmine Setup
The Angular CLI does the heavy lifting of setting up the whole testing environment for us:
ng test
With everything in place you can start using the Jasmine test framework together
with the Angular Testing Utilities to write your Unit Tests.
The Strategies
PREPARE THE FIELD, LEARN THE TOOLS
When thinking about testing you should:
•Work in a highly controlled environment.
•Keep the things simple, avoid using too many external libraries.
Two kinds of unit tests…
…that will allow us to learn how to write tests in an incremental way.
Pure Unit Testing (using Jasmine / Karma).
Angular Unit Testing (using Jasmine / Karma + Angular Testing Utilities).
Pure Unit Testing
Pure Unit Testing
Try to keep the things simple: just use what the frameworks offers us.
Good to test: Services, Pipes and Components'controllers.
Skip dependency injection, create instances of classes directly (using the constructors).
Pure Unit Testing
Pros:
•Easy to setup and understand.
•‘Very little’ to know, ‘just’ the test frameworks.
•Tests are easy to write.
Cons:
•Limited capabilities, you can only test services, pipes and components' controllers.
•Cannot test the DOM, nor the interaction between the component and its template (bindings).
•Testing a component might have little to no meaning at all (the component might not have any logic).
Pure Unit Tests
These kinds of test allows us to introduce:
•How Jasmine works (test setup & expectation checks).
•How to use some Test Doubles (dummy / fake / stubs / spies).
•How to do sync tests with Jasmine.
•How to do async tests with Jasmine.
•Learn techniques we can use in full Angular Tests.
TypeScript: an unexpected ally!
It helps us reducing the number of tests we need to setup:
•It helps us avoiding errors when we write tests, because it provide us:
• Intellisense.
• Code completion and code navigation.
• Syntax checking and type checking (even on some 'string literals', given the use of the new 'key of'
operator, see the spyOn sample).
•No more trivial tests to validate function parameters calls.
•No more trivial tests to check for implicit type conversion (or nullability, but depends on some
compiler switches).
Demos
PURE UNIT TESTS IN ACTIONS
GitHub
https://github.com/AGiorgetti/
AngularUnitTestingShowcase
Jasmine: test setup & sync tests
// Jasmine uses describe() to setup a test suite
describe('00 - Pure Test - Init - AuthService', () => {
let sut: AuthService;
// Jasmine runs the beforEach() functions before each test.
// Resets the configuration before each test, it will provide you
// with a clean environment every time.
// You can have more than one beforeEach() in a test suite, they will be executed in the correct order.
beforeEach(() => {
// no dependency injection, create everything with constructors
sut = new AuthService(new ApiAuthService());
});
// Jasmine uses 'it()' to define a single test case.
it("should login a user", () => {
sut.login("Alessandro", "12345");
expect(sut.isLoggedIn).toBeTruthy();
expect(sut.username).toBe("Alessandro");
});
app/unittests/00-pure-unit-tests/pure-tests-00-initialization.spec.ts
Jasmine: async tests & async/await
// Async Test: Jasmine will wait for a done() function call that will mark
// all the async test operation as completed.
it("(done()) should login a user", (done) => {
sut.loginAsync("Alessandro", "12345")
.then(result => {
expect(result).toBeTruthy();
expect(sut.isLoggedIn).toBeTruthy();
expect(sut.username).toBe("Alessandro");
// call done when all your expectation are verified!
done();
});
});
// Async Test, make it more readable with async/await;
// the function is still async, and we still might to call done().
it("(async/await) should login a user", async (done) => {
const result = await sut.loginAsync("Alessandro", "12345");
expect(result).toBeTruthy();
expect(sut.isLoggedIn).toBeTruthy();
expect(sut.username).toBe("Alessandro");
// call done when all your expectation are verified!
done();
});
app/unittests/00-pure-unit-tests/pure-tests-01-sync-async.spec.ts
Classic async test with promises
TypeScript async/await
Jasmine: async tests – done()
Forgetting to call the done() while doing async tests will lead to unpredictable results:
•Test displayed as green while no actual expectation has been already checked.
•Errors that will be displayed in the console only (if you have it open).
•Mixed results: the failing expectations can be displayed as part of the next test in line.
app/unittests/00-pure-unit-tests/pure-tests-01-sync-async.spec.ts
Jasmine: stub object
// What if our system under test has some dependencies ?
// Using the 'Real Services' is always a problem, we need to provide Test Doubles.
// Provide a Stub object (that implements the same interface of the original object)
// this way we can control the testing environment and test the component in isolation.
// It has the advantage of reducing the total number of dependencies of the unit.
describe('03 - Pure Test - using a Stub object', () => {
let authApiServiceStub: AuthApiService;
let sut: AuthService;
beforeEach(() => {
// create a stub object, we can control the test implementing / changing its behavior on the fly.
// we also have TypeScript to help us here (in case of refactoring).
authApiServiceStub = <AuthApiService>{};
authApiServiceStub.login = (username: string, password: string) => Promise.resolve(true);
sut = new AuthService(authApiServiceStub);
});
app/unittests/00-pure-unit-tests/pure-tests-03-stub.spec.ts
Jasmine: spy / spyOn
// What if our system under test has some dependencies ?
// Using the 'real services' is always a problem, we need to provide Test Doubles.
// Provide a Stub, this way we can control the testing environment and
// check the component in isolation.
// Use Jasmine 'spyOn' to instrument and change the behavior of the real object.
// We can also use it to check for expectations.
describe('02 - Pure Test - spyOn - AuthApiService', () => {
let authApiService: AuthApiService;
let sut: AuthService;
let loginSpy: jasmine.Spy;
beforeEach(() => {
authApiService = new AuthApiService();
sut = new AuthService(authApiService);
// a spy can be used to provide canned return values to function calls.
loginSpy = spyOn(authApiService, "login");
// .and.callThrough(); // instrument and delegate to the original function
// .and.returnValue(false); // provide a return value, can also provide custom behavior with 'callFake'
});
app/unittests/00-pure-unit-tests/pure-tests-02-spyOn.spec.ts
Jasmine: spy / spyOn
// Change behavior using a 'Spy'
it("should have no logged user if login fails", async (done) => {
// always fail the login procedure (this changes the service behavior)
loginSpy.and.returnValue(false);
const result = await sut.loginAsync("Alessandro", "12345");
expect(loginSpy.calls.count()).toBe(1);
expect(result).toBeFalsy();
expect(sut.isLoggedIn).toBeFalsy();
expect(sut.username).toBe("");
done();
});
it("should have no logged user if the http call fails (fake)", async (done) => {
// always fail the login procedure (this changes the service behavior)
loginSpy.and.callFake((username: string, password: string) => { throw new Error("http error!") });
try {
const result = await sut.loginAsync("Alessandro", "12345");
} catch (e) {
expect((e as Error).message).toBe("http error!");
}
expect(loginSpy.calls.count()).toBe(1);
expect(sut.isLoggedIn).toBeFalsy();
expect(sut.username).toBe("");
done();
});
app/unittests/00-pure-unit-tests/pure-tests-02-spyOn.spec.ts
Jasmine: stub & spy
// Jasmine can also mix both approaches:
// - create a stub object.
// - augment it using a spy to trace the function calls.
beforeEach(() => {
// create a stub object, we can control the test implementing its behavior on the
fly
authApiServiceStub = <AuthApiService>{};
authApiServiceStub.login = (username: string, password: string) =>
Promise.resolve(true);
loginSpy = spyOn(authApiServiceStub, "login");
sut = new AuthService(authApiServiceStub);
});
app/unittests/00-pure-unit-tests/pure-tests-04-stub-spyOn.spec.ts
Jasmine & Angular Utilities: async()
// async() will call jasmine done() function for us when all the async operation
// started in the async test zone complete themselves.
it("(async()) should login a user", async(() => {
sut.loginAsync("Alessandro", "12345")
.then(result => {
expect(result).toBeTruthy();
expect(sut.isLoggedIn).toBeTruthy();
expect(sut.username).toBe("Alessandro");
});
}));
app/unittests/00-pure-unit-tests/pure-tests-05-async-testing-utilities.spec.ts
done() will be called by Angular
Jasmine & Angular Utilities: fakeAsync()
// fakeAsync() + tick() allows us to write async tests in a more linear coding style:
// the tests appear to be synchronous.
// WARNING: cannot make XHR calls inside a fakeAsync zone!
it("(fakeAsync(), no spyOn) should login a user", fakeAsync(() => {
let result: boolean;
sut.loginAsync("Alessandro", "12345")
.then(res => result = res);
// tick() simulates the asynchronous passage of time.
tick(500); // the functions inside the async call have a 500 ms delay before completing
expect(result).toBeTruthy();
expect(sut.isLoggedIn).toBeTruthy();
expect(sut.username).toBe("Alessandro");
}));
There are still some problems with fakeAsync and async/await, setTimeout, setInterval, and some RxJS operators...
app/unittests/00-pure-unit-tests/pure-tests-05-async-testing-utilities.spec.ts
‘Angular’ Unit Testing
LET’S ENHANCE OUR TESTING EXPERIENCE!
Angular Unit Testing
What if we want to simulate the component as if it's part of a 'real' Angular application ?
With the dependency injection, template rendering, bindings and DOM interactions?
Introducing:
TestBed and the Angular Testing Utilities!
Angular Unit Testing
Pros:
•Extremely powerful.
•Allows to test services and components (services, controllers, templates, bindings) in isolation.
•Allows to test components and services interactions (@Input, @Output).
Cons:
•Take into account async operations since the start.
•Need to consider the change detection mechanics (you must know how Angular works).
•Tests initialization can be complex, you need to configure a fake ‘NgModule' with lots of moving parts.
•Complex tests need a deep knowledge of Angular Testing Utilities and Test Doubles for components
(Http, Router, …).
TestBed - definition
A testbed (also "test bed") is a platform for conducting rigorous, transparent, and replicable
testing of scientific theories, computational tools, and new technologies.
In software development testbedding is a method of testing a particular module (function, class,
or library) in an isolated fashion.
It may be used as a proof of concept or when a new module is tested apart from the
program/system it will later be added to.
TestBed & Angular Testing Utilities
They are available importing: '@angular/core/testing'.
TestBed is used to create an instance of a dynamically generated NgModule that will be
configured to supply the system under test and all the needed Test Doubles (components,
directives, service mocks, etc...).
beforEach() test the whole module is resetted to the starting state.
TestBed - API
Use TestBed to configure a dynamically generated module environment:
•.configureTestingModule() - takes a metadata object very close to the one used to define a real
Angular module.
The default testing module is configured with basic declaratives and some Angular service substitutes that every tester needs.
•.compileComponents() - compile the testing module asynchronously. You must call this method
if any of the testing module components have a templateUrl or styleUrls property.
After calling compileComponents, the TestBed configuration is frozen for the duration of the current spec.
•.createComponent() - create an instance of a component of type T.
After calling compileComponent, the TestBed configuration is frozen for the duration of the current spec.
Angular Stand-alone Testing Utilities
Angular also provides some utility function that aim to simplify how tests are written.
Some of the most used:
•async() – runs the setup or the body of the test in a special async zone, ‘waiting’ for tasks to complete before
moving to the next step.
•fakeAsync() + tick() – runs the body of the test in a special fake async zone, allowing for a more linear control
flow.
•Inject() – injects services from the current TestBed instance.
•By – an helper class whose methods are used to build query predicates.
There are also many other functions that can be used to fine tune the tests (discardPeriodicTasks(), flushMicrotasks(), …).
Demos
ANGULAR UNIT TESTS IN ACTIONS
GitHub
https://github.com/AGiorgetti/
AngularUnitTestingShowcase
Angular Tests - setup
describe('00 - Angular Tests - initialization - AppComponent', () => {
// Jarmine runs the beforEach() function before each test to
// reset the configuration of the testing TestBed NgModule before each test, it will provide you
// with a clean environment every time.
// You can have more than one beforeEach() in a test suite, they will be executed in the correct order.
beforeEach(async(() => {
// the component has external resources, and we need to give the compiler time to read them
// the async() Angular test function will arrange the things so that the code is run in a special async test zone.
// All the tests will be executed after any async operation started in the beforEach has been completed.
// TestBed is used to define a dynamically generated NgModule.
TestBed.configureTestingModule({
declarations: [
AppComponent
]
}).compileComponents();
// calling 'compileComponents()' locks down the testing module. No more configuration
// or override methods calls are allowed after this call.
// If you don't call .compileComponents(), the first call to .createComponent() will
// lock down the TestBed module too.
// WebPack users do not need to call .compileComponents(), everything is inlined during the build phase.
}));
app/unittests/01-angular-testing/angular-tests-00-initialization.spec.ts
ComponentFixture
TestBed.createComponent() returns a 'ComponentFixture', a construct that gives access to:
•componentInstance: a handle the component's controller.
•debugElement: a handle to the component's DOM element.
Angular Tests - ComponentFixture
it('should create the app', () => {
// use .createComponent() to get a ComponentFixture object.
// A ComponentFixture is what you use to gain access to the component (componentInstance)
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
expect(app.title).toBe("app");
});
it("should not have any title in the DOM until Angular calls for change detection.", () => {
// use .createComponent() to get a ComponentFixture object.
// A ComponentFixture is what you use to gain access to the component DOM nodes (debugElement)
const fixture = TestBed.createComponent(AppComponent);
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent.trim()).toEqual("Welcome to");
});
app/unittests/01-angular-testing/angular-tests-00-initialization.spec.ts
ChangeDetection
By Design(tm) Angular testing framework does not trigger Change Detection automatically, you need to do that
manually calling:
ComponentFixture.detectChanges()
•It gives us a chance to test the component in an uninitialized state, and check what happens to the template
before and after the bindings did their magic.
•It also means that: changing a property in the component as a synchronous operation will be invisible to
Angular untill we call detectChanges() explicitly (even with the automatic detect changes in place).
The default behavior can be changed setting:
{ provide: ComponentFixtureAutoDetect, useValue: true }
Angulat Tests – detectChanges()
// changeDetection() is not automatic, this is intentional, so the user
// has a chance to inspect the component before Angular does its magic.
// You can change this behavior configuring ComponentFixtureAutoDetect, like this:
// { provide: ComponentFixtureAutoDetect, useValue: true }
// The ComponentFixtureAutoDetect service responds to asynchronous activities such as promise resolution,
// timers, and DOM events.
it("should not have any title in the DOM until manually call 'detectChanged'", () => {
const fixture = TestBed.createComponent(AppComponent);
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent.trim()).toEqual("Welcome to");
});
it('should render title in a h1 tag', () => {
const fixture = TestBed.createComponent(AppComponent);
// ask Angular to apply its change detection cycle (all the bindings will be evaluated).
// Angular responds to asynchronous activities such as promise resolution, timers, and DOM events.
// WARNING!!! A direct, synchronous update of the component property is invisible.
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
});
app/unittests/01-angular-testing/angular-tests-01-detectChanges.spec.ts
Component with Dependencies
In order to control the environment we need to provide substitutes for the component dependencies.
We can follow the same approaches we saw in the ‘Pure Tests’ scenarios:
•Provide a Stub Object.
•Spy on the Real Service.
•Spy on a Stub Object.
We’ll use dependency injection to supply services to our
components!
Component with Dependencies
There’s one recommendation:
if you need to interact with the injected services always get them from the component’s injector!
(accessible through the ComponentFixture.debugElement.injector property).
You can also get an instance of the service calling:
•TestBed.get()
•Inject()
Angular Tests – stub object / D.I.
// Always get the service from an Injector
// do not reference this instance inside the tests anymore, the instance that will be
// injected in the component is a clone - something different - of this object!
describe('02 - Angular Tests - with dep. - GreetingsComponent - Stub Injected Service',
() => {
let component: GreetingsComponent;
let fixture: ComponentFixture<GreetingsComponent>;
// the stub definition object
const authServiceStub = <AuthService>{
isLoggedIn: false
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [GreetingsComponent],
providers: [
{ provide: AuthService, useValue: authServiceStub }
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(GreetingsComponent);
component = fixture.componentInstance;
// avoid calling the detectChanges() automatically,
// we have a chance to interact with the services before the bindings are evaluated
// fixture.detectChanges();
});
// Get the service from an injector!
// 3 Ways to do it:
// 1- from the Component's Injector
// The way that will always work (angular has a ierarchy of injectors) is to ask the
component's injector
// (we can access it through the fixture).
it("should access the injected service from the Component's Injector", () => {
const auth = fixture.debugElement.injector.get(AuthService);
expect(auth).not.toBeNull();
});
// 2- from TestBed.get() if the service is registered with the module
it("should access the injected service from the TestBed.get()", () => {
const auth = TestBed.get(AuthService);
expect(auth).not.toBeNull();
});
// 3- using the inject() utility function if the service is registered with the module
it("should access the injected service from the TestBed.get()",
inject([AuthService], (auth) => {
expect(auth).not.toBeNull();
})
);
app/unittests/01-angular-testing/angular-tests-02-component-withDep.spec.ts
Angular Tests – async testing
Always take into account the async nature of Angular (starting from how change detection works):
•We can use the same techniques we saw in the ‘Pure Test’ scenarios.
•Angular offers us async() and fakeAsync() standalone helper functions to make our life way easier writing tests.
We already saw async() in action during the tests setup:
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [GreetingsAsyncComponent],
providers: [AuthApiService, AuthService]
})
.compileComponents();
}));
app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
… test setup context …
beforeEach(() => {
fixture = TestBed.createComponent(GreetingsAsyncComponent);
component = fixture.componentInstance;
authService = fixture.debugElement.injector.get(AuthService);
// add a spy that provides the test with the proper initialization
// we simulate having a user already authenticated, the server have to provide the
// data.
getLoggedUserAsyncSpy = spyOn(authService, "getLoggedUserAsync")
.and.returnValue(Promise.resolve("Alessandro"));
// .and.callThrough(); // delegating to functions with timers might create problems to Angular
testing utilities
el = fixture.debugElement.query(By.css("h3")).nativeElement;
// will call this in the actual tests, to check for initialized state
// fixture.detectChanges();
});
app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
Angular Tests – async()
// async() - Angular Testing Utility function
it('should show greetings after getLoggedUserAsync promise (async)', async(() => {
// force change detection, calls ngOnInit
fixture.detectChanges();
// wait for the async function to complete (async test zone)
fixture.whenStable()
.then(() => {
// force a change detection to update the view
// (the tests does not do it automatically)
fixture.detectChanges();
expect(el.textContent).toBe("welcome, Alessandro");
});
}));
app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
Angular Tests – fakeAsync() / tick()
// fakeAsync() - Angular Testing Utility function
// Enables a more linear coding style.
// WARNING: cannot make XHR calls inside a fakeAsync()
it('should show greetings after getLoggedUserAsync promise (fakeAsync)',
fakeAsync(() => {
// force change detection, calls ngOnInit
fixture.detectChanges();
// wait for the async functions to complete (fake async zone)
tick(); // use tick(500) when you set .and.callThrough() on the spy
// force a change detection to update the view
fixture.detectChanges();
expect(el.textContent).toBe("welcome, Alessandro");
}));
app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
Angular Tests – async ‘the jasmine way’
// sometimes we need to use the traditional jasmine way to do async tests
// especially considering there may be problems with timers and xhr calls
it('should show greetings after getLoggedUserAsync promise (jasmine)', done => {
// force change detection, calls ngOnInit
fixture.detectChanges();
// use the spy to be notified when the inner function call ends
getLoggedUserAsyncSpy.calls.mostRecent().returnValue
.then(() => {
// force a change detection to update the view
fixture.detectChanges();
expect(el.textContent).toBe("welcome, Alessandro");
done();
});
});
app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
Override Configuration
Sometimes registering the providers with the test module is not enough, a component can define
it's own dependency injection list, and we cannot directly stub the component's services in the
dynamically generated test module (they are declared in the component metadata).
What we can do is: override the component configuration and add, remove or set the metadata
of the component:
•TestBed.overrideComponent()
•TestBed.overrideDirective()
•TestBed.overrideModule()
•TestBed.overridePipe()
•TestBed.overrideTemplate()
.overrideComponent(MyComponent, {
set: {
providers: [
{ provide: Service, useClass: ServiceSpy}
]
}
})
.compileComponents();
entryComponents: []
TestBed actually does not have a way to define the entryComponents metadata.
Workaround:
•Define a new NgModule declaring all the needed entryComponents.
•Import the EntryComponents-NgModule in the TestBed.configureTestingModule() metadata.
Test @Input and @Output
Two strategies:
•Test the component stand-alone, emulating the interaction with the rest of the world.
Set the input properties and subscribe to the output properties
(we have access to component’s controller through the ComponentFixture).
•Create a Test Double (a very simple TestHostComponent), that can instantiate and use the
component under test. Use the test double to drive the nested component and verify what
happens (both in its controller and in its view).
Code Coverage
Code Coverage
Code Coverage is a measure used to describe the degree to which the source code of a program
is executed when a particular test suite runs.
Angular CLI does the heavy lifting again and setup the code coverage analysis for us.
Run the tests with:
ng test --single-run=true --code-coverage
You can configure the report output in the karma.config.js file.
Application Lifecycle
Management
ADD THE TEST SUITE TO A CONTINOUS INTEGRATION TOOLS
Integrate your build with VSTS
Configure Karma for:
•Single unit test execution.
•Output unit test result in a parsable format.
•Output code coverage information in a parsable format.
Configure VSTS (other services behave differently) to:
•On demand or Countinously build the application.
•Get the source files, ‘npm install’ the packages and build the application.
•Run the unit test suite.
•Display the build / tests / code coverage results.
Karma & Visual Studio Team Services
Karma.config.js
• Add a karma reporter plugin that can be parsed by VSTS: "karma-nunit2-reporter“.
• Configure karma to report the unit test results in “nunit” format.
• Configure Karma to output the code coverage analysis in “cobertura” format.
module.exports = function (config) {
config.set({
plugins: [
…
require('karma-nunit2-reporter')],
…
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly', 'cobertura' ],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml', 'nunit'],
nunitReporter: {
outputFile: 'test-results.xml',
suite: ''
},
…
});
};
package.json:
• Add the required plugin to emit the information in nunit format:
• create a script to execute the tests and the code coverage analisys.
• Test the script: “npm run vststest”
{
"name": "unit-tests",
"scripts": {
…
"vststest": "ng test --single-run=true --code-coverage --reporters nunit"
},
…
"devDependencies": {
…
"karma-nunit2-reporter": "0.3.0",
}
}
Configure VSTS to display the results
Configure VSTS to display the results
Configure VSTS to display the results
Configure VSTS to display the results
VSTS: the build report
Thanks All!
Q. & (maybe) A. !
Who am I ?
Dott.ing. Alessandro Giorgetti
Facebook: https://www.facebook.com/giorgetti.alessandro
Twitter: @a_giorgetti
LinkedIn: https://it.linkedin.com/in/giorgettialessandro
E-mail: alessandro.giorgetti@live.com
Blog: www.primordialcode.com
Alessandro Giorgetti
www.primordialcode.com

Más contenido relacionado

La actualidad más candente

Unit Testing And Mocking
Unit Testing And MockingUnit Testing And Mocking
Unit Testing And MockingJoe Wilson
 
Unit testing JavaScript: Jasmine & karma intro
Unit testing JavaScript: Jasmine & karma introUnit testing JavaScript: Jasmine & karma intro
Unit testing JavaScript: Jasmine & karma introMaurice De Beijer [MVP]
 
UNIT TESTING PPT
UNIT TESTING PPTUNIT TESTING PPT
UNIT TESTING PPTsuhasreddy1
 
Mockito a simple, intuitive mocking framework
Mockito   a simple, intuitive mocking frameworkMockito   a simple, intuitive mocking framework
Mockito a simple, intuitive mocking frameworkPhat VU
 
05 junit
05 junit05 junit
05 junitmha4
 
Unit Testing Concepts and Best Practices
Unit Testing Concepts and Best PracticesUnit Testing Concepts and Best Practices
Unit Testing Concepts and Best PracticesDerek Smith
 
Automation Testing with Test Complete
Automation Testing with Test CompleteAutomation Testing with Test Complete
Automation Testing with Test CompleteVartika Saxena
 
Unit testing best practices
Unit testing best practicesUnit testing best practices
Unit testing best practicesnickokiss
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with MockitoRichard Paul
 
Robot Framework Introduction
Robot Framework IntroductionRobot Framework Introduction
Robot Framework IntroductionPekka Klärck
 

La actualidad más candente (20)

Unit Testing And Mocking
Unit Testing And MockingUnit Testing And Mocking
Unit Testing And Mocking
 
Unit Testing (C#)
Unit Testing (C#)Unit Testing (C#)
Unit Testing (C#)
 
Unit Testing
Unit TestingUnit Testing
Unit Testing
 
Unit testing JavaScript: Jasmine & karma intro
Unit testing JavaScript: Jasmine & karma introUnit testing JavaScript: Jasmine & karma intro
Unit testing JavaScript: Jasmine & karma intro
 
Junit
JunitJunit
Junit
 
UNIT TESTING PPT
UNIT TESTING PPTUNIT TESTING PPT
UNIT TESTING PPT
 
Introduction to JUnit
Introduction to JUnitIntroduction to JUnit
Introduction to JUnit
 
Mockito a simple, intuitive mocking framework
Mockito   a simple, intuitive mocking frameworkMockito   a simple, intuitive mocking framework
Mockito a simple, intuitive mocking framework
 
Java Unit Testing
Java Unit TestingJava Unit Testing
Java Unit Testing
 
Rest assured
Rest assuredRest assured
Rest assured
 
Introduction to Software Test Automation
Introduction to Software Test AutomationIntroduction to Software Test Automation
Introduction to Software Test Automation
 
05 junit
05 junit05 junit
05 junit
 
Unit Testing Concepts and Best Practices
Unit Testing Concepts and Best PracticesUnit Testing Concepts and Best Practices
Unit Testing Concepts and Best Practices
 
Automation Testing with Test Complete
Automation Testing with Test CompleteAutomation Testing with Test Complete
Automation Testing with Test Complete
 
TestNG Framework
TestNG Framework TestNG Framework
TestNG Framework
 
Unit testing best practices
Unit testing best practicesUnit testing best practices
Unit testing best practices
 
Cypress Automation
Cypress  AutomationCypress  Automation
Cypress Automation
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
 
Robot Framework Introduction
Robot Framework IntroductionRobot Framework Introduction
Robot Framework Introduction
 
JUNit Presentation
JUNit PresentationJUNit Presentation
JUNit Presentation
 

Similar a Angular Unit Testing

Describe's Full of It's
Describe's Full of It'sDescribe's Full of It's
Describe's Full of It'sJim Lynch
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSUnit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSKnoldus Inc.
 
Java Unit Test - JUnit
Java Unit Test - JUnitJava Unit Test - JUnit
Java Unit Test - JUnitAktuğ Urun
 
Software Testing
Software TestingSoftware Testing
Software TestingAdroitLogic
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testingpleeps
 
Intro To Unit and integration Testing
Intro To Unit and integration TestingIntro To Unit and integration Testing
Intro To Unit and integration TestingPaul Churchward
 
Intro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJSIntro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJSJim Lynch
 
Embrace Unit Testing
Embrace Unit TestingEmbrace Unit Testing
Embrace Unit Testingalessiopace
 
Rails Testing
Rails TestingRails Testing
Rails Testingmikeblake
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentAll Things Open
 
Oh so you test? - A guide to testing on Android from Unit to Mutation
Oh so you test? - A guide to testing on Android from Unit to MutationOh so you test? - A guide to testing on Android from Unit to Mutation
Oh so you test? - A guide to testing on Android from Unit to MutationPaul Blundell
 
Model Driven Testing: requirements, models & test
Model Driven Testing: requirements, models & test Model Driven Testing: requirements, models & test
Model Driven Testing: requirements, models & test Gregory Solovey
 
Unit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex ScenariosUnit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex ScenariosFlutter Agency
 
Protractor framework architecture with example
Protractor framework architecture with exampleProtractor framework architecture with example
Protractor framework architecture with exampleshadabgilani
 
Unit testing php-unit - phing - selenium_v2
Unit testing   php-unit - phing - selenium_v2Unit testing   php-unit - phing - selenium_v2
Unit testing php-unit - phing - selenium_v2Tricode (part of Dept)
 

Similar a Angular Unit Testing (20)

Describe's Full of It's
Describe's Full of It'sDescribe's Full of It's
Describe's Full of It's
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSUnit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJS
 
Java Unit Test - JUnit
Java Unit Test - JUnitJava Unit Test - JUnit
Java Unit Test - JUnit
 
Software Testing
Software TestingSoftware Testing
Software Testing
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Intro To Unit and integration Testing
Intro To Unit and integration TestingIntro To Unit and integration Testing
Intro To Unit and integration Testing
 
Intro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJSIntro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJS
 
Unit testing - A&BP CC
Unit testing - A&BP CCUnit testing - A&BP CC
Unit testing - A&BP CC
 
Embrace Unit Testing
Embrace Unit TestingEmbrace Unit Testing
Embrace Unit Testing
 
Rails Testing
Rails TestingRails Testing
Rails Testing
 
Unit testing basic
Unit testing basicUnit testing basic
Unit testing basic
 
Unit Testing in Java
Unit Testing in JavaUnit Testing in Java
Unit Testing in Java
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
Oh so you test? - A guide to testing on Android from Unit to Mutation
Oh so you test? - A guide to testing on Android from Unit to MutationOh so you test? - A guide to testing on Android from Unit to Mutation
Oh so you test? - A guide to testing on Android from Unit to Mutation
 
Unit test
Unit testUnit test
Unit test
 
Model Driven Testing: requirements, models & test
Model Driven Testing: requirements, models & test Model Driven Testing: requirements, models & test
Model Driven Testing: requirements, models & test
 
Unit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex ScenariosUnit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex Scenarios
 
Protractor framework architecture with example
Protractor framework architecture with exampleProtractor framework architecture with example
Protractor framework architecture with example
 
Unit testing php-unit - phing - selenium_v2
Unit testing   php-unit - phing - selenium_v2Unit testing   php-unit - phing - selenium_v2
Unit testing php-unit - phing - selenium_v2
 

Más de Alessandro Giorgetti

The Big Picture - Integrating Buzzwords
The Big Picture - Integrating BuzzwordsThe Big Picture - Integrating Buzzwords
The Big Picture - Integrating BuzzwordsAlessandro Giorgetti
 
AngularConf2016 - A leap of faith !?
AngularConf2016 - A leap of faith !?AngularConf2016 - A leap of faith !?
AngularConf2016 - A leap of faith !?Alessandro Giorgetti
 
TypeScript . the JavaScript developer best friend!
TypeScript . the JavaScript developer best friend!TypeScript . the JavaScript developer best friend!
TypeScript . the JavaScript developer best friend!Alessandro Giorgetti
 
«Real Time» Web Applications with SignalR in ASP.NET
«Real Time» Web Applications with SignalR in ASP.NET«Real Time» Web Applications with SignalR in ASP.NET
«Real Time» Web Applications with SignalR in ASP.NETAlessandro Giorgetti
 
DNM19 Sessione1 Orchard Primo Impatto (ita)
DNM19 Sessione1 Orchard Primo Impatto (ita)DNM19 Sessione1 Orchard Primo Impatto (ita)
DNM19 Sessione1 Orchard Primo Impatto (ita)Alessandro Giorgetti
 
DNM19 Sessione2 Orchard Temi e Layout (Ita)
DNM19 Sessione2 Orchard Temi e Layout (Ita)DNM19 Sessione2 Orchard Temi e Layout (Ita)
DNM19 Sessione2 Orchard Temi e Layout (Ita)Alessandro Giorgetti
 

Más de Alessandro Giorgetti (9)

Microservices Architecture
Microservices ArchitectureMicroservices Architecture
Microservices Architecture
 
Let's talk about... Microservices
Let's talk about... MicroservicesLet's talk about... Microservices
Let's talk about... Microservices
 
The Big Picture - Integrating Buzzwords
The Big Picture - Integrating BuzzwordsThe Big Picture - Integrating Buzzwords
The Big Picture - Integrating Buzzwords
 
AngularConf2016 - A leap of faith !?
AngularConf2016 - A leap of faith !?AngularConf2016 - A leap of faith !?
AngularConf2016 - A leap of faith !?
 
AngularConf2015
AngularConf2015AngularConf2015
AngularConf2015
 
TypeScript . the JavaScript developer best friend!
TypeScript . the JavaScript developer best friend!TypeScript . the JavaScript developer best friend!
TypeScript . the JavaScript developer best friend!
 
«Real Time» Web Applications with SignalR in ASP.NET
«Real Time» Web Applications with SignalR in ASP.NET«Real Time» Web Applications with SignalR in ASP.NET
«Real Time» Web Applications with SignalR in ASP.NET
 
DNM19 Sessione1 Orchard Primo Impatto (ita)
DNM19 Sessione1 Orchard Primo Impatto (ita)DNM19 Sessione1 Orchard Primo Impatto (ita)
DNM19 Sessione1 Orchard Primo Impatto (ita)
 
DNM19 Sessione2 Orchard Temi e Layout (Ita)
DNM19 Sessione2 Orchard Temi e Layout (Ita)DNM19 Sessione2 Orchard Temi e Layout (Ita)
DNM19 Sessione2 Orchard Temi e Layout (Ita)
 

Último

W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceanilsa9823
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 

Último (20)

W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 

Angular Unit Testing

  • 1. Angular Unit Testing DO I REALLY NEED TO DO IT ? Alessandro Giorgetti www.primordialcode.com
  • 3. Do I really have to do it?
  • 4. Short answer: Are you serious ?! We just HATE deliver bad / malfunctioning code! But we need to choose wisely what to test!
  • 5. It’s like a war! The operating scenario: «Angular Application». •Composition of components and services (lots of moving parts). •Interactions between components and services. •Interactions between users and the application. Best of all: •Most of these Interactions are ASYNC!
  • 6. We cannot face the fight alone! We need some help: •Take advantage of Unit Testing Frameworks, Tools & Utilities •Surround the System Under Test with Test Doubles. •Instrument the function calls and/or replace object behavior with something faked for testing purposes. •Deal with Asynchronous testing code.
  • 7. Definition: Unit Testing The definition is actually pretty vague! We can define them by the signature points: •Unit Tests focus on testing small parts (units) of the software system. •Unit Tests are expected to verify few targetted assertions. •Unit Tests are expected to be fast.
  • 8. Definition: Test Double Objects or Procedures that look and behave like their release-intended counterparts, but are actually simplified versions that reduce the complexity and facilitate testing. Like the Stunt-Doubles used in the film-making industry.
  • 9. Several Types of Test Doubles •Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists. •Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an InMemoryTestDatabase is a good example). •Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. •Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent. •Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting. Source: martinfowler.com - https://martinfowler.com/bliki/TestDouble.html
  • 10. The question is: How to do Unit Tests in Angular ?
  • 11. Testing Frameworks JASMINE / KARMA PROTRACTOR
  • 12. Jasmine / Karma / Protractor Jasmine is a behavior driven test framework, it can be used to test components, services and even DOM elements. http://jasmine.github.io/ Karma is a test runner that was designed to run low level Unit Tests (those that involve single components, directives and services). https://karma-runner.github.io Protractor is an end to end test framework that runs tests against the real application running in a real instance of the browser (without component mocking). http://www.protractortest.org/
  • 13. Preparing the battlefield Setting up all these frameworks is outside the scope of this talk. 1. We can setup everything from scratch. 2. We can use seeding projects / startup projects with preconfigured environment. 3. Use the consolidated Angular CLI to generate the preconfigured project for us. Let’s go with option 3, we can fine tune some configurations options later!
  • 14. Karma / Jasmine Setup The Angular CLI does the heavy lifting of setting up the whole testing environment for us: ng test With everything in place you can start using the Jasmine test framework together with the Angular Testing Utilities to write your Unit Tests.
  • 15. The Strategies PREPARE THE FIELD, LEARN THE TOOLS
  • 16. When thinking about testing you should: •Work in a highly controlled environment. •Keep the things simple, avoid using too many external libraries.
  • 17. Two kinds of unit tests… …that will allow us to learn how to write tests in an incremental way. Pure Unit Testing (using Jasmine / Karma). Angular Unit Testing (using Jasmine / Karma + Angular Testing Utilities).
  • 19. Pure Unit Testing Try to keep the things simple: just use what the frameworks offers us. Good to test: Services, Pipes and Components'controllers. Skip dependency injection, create instances of classes directly (using the constructors).
  • 20. Pure Unit Testing Pros: •Easy to setup and understand. •‘Very little’ to know, ‘just’ the test frameworks. •Tests are easy to write. Cons: •Limited capabilities, you can only test services, pipes and components' controllers. •Cannot test the DOM, nor the interaction between the component and its template (bindings). •Testing a component might have little to no meaning at all (the component might not have any logic).
  • 21. Pure Unit Tests These kinds of test allows us to introduce: •How Jasmine works (test setup & expectation checks). •How to use some Test Doubles (dummy / fake / stubs / spies). •How to do sync tests with Jasmine. •How to do async tests with Jasmine. •Learn techniques we can use in full Angular Tests.
  • 22. TypeScript: an unexpected ally! It helps us reducing the number of tests we need to setup: •It helps us avoiding errors when we write tests, because it provide us: • Intellisense. • Code completion and code navigation. • Syntax checking and type checking (even on some 'string literals', given the use of the new 'key of' operator, see the spyOn sample). •No more trivial tests to validate function parameters calls. •No more trivial tests to check for implicit type conversion (or nullability, but depends on some compiler switches).
  • 23. Demos PURE UNIT TESTS IN ACTIONS
  • 25. Jasmine: test setup & sync tests // Jasmine uses describe() to setup a test suite describe('00 - Pure Test - Init - AuthService', () => { let sut: AuthService; // Jasmine runs the beforEach() functions before each test. // Resets the configuration before each test, it will provide you // with a clean environment every time. // You can have more than one beforeEach() in a test suite, they will be executed in the correct order. beforeEach(() => { // no dependency injection, create everything with constructors sut = new AuthService(new ApiAuthService()); }); // Jasmine uses 'it()' to define a single test case. it("should login a user", () => { sut.login("Alessandro", "12345"); expect(sut.isLoggedIn).toBeTruthy(); expect(sut.username).toBe("Alessandro"); }); app/unittests/00-pure-unit-tests/pure-tests-00-initialization.spec.ts
  • 26. Jasmine: async tests & async/await // Async Test: Jasmine will wait for a done() function call that will mark // all the async test operation as completed. it("(done()) should login a user", (done) => { sut.loginAsync("Alessandro", "12345") .then(result => { expect(result).toBeTruthy(); expect(sut.isLoggedIn).toBeTruthy(); expect(sut.username).toBe("Alessandro"); // call done when all your expectation are verified! done(); }); }); // Async Test, make it more readable with async/await; // the function is still async, and we still might to call done(). it("(async/await) should login a user", async (done) => { const result = await sut.loginAsync("Alessandro", "12345"); expect(result).toBeTruthy(); expect(sut.isLoggedIn).toBeTruthy(); expect(sut.username).toBe("Alessandro"); // call done when all your expectation are verified! done(); }); app/unittests/00-pure-unit-tests/pure-tests-01-sync-async.spec.ts Classic async test with promises TypeScript async/await
  • 27. Jasmine: async tests – done() Forgetting to call the done() while doing async tests will lead to unpredictable results: •Test displayed as green while no actual expectation has been already checked. •Errors that will be displayed in the console only (if you have it open). •Mixed results: the failing expectations can be displayed as part of the next test in line. app/unittests/00-pure-unit-tests/pure-tests-01-sync-async.spec.ts
  • 28. Jasmine: stub object // What if our system under test has some dependencies ? // Using the 'Real Services' is always a problem, we need to provide Test Doubles. // Provide a Stub object (that implements the same interface of the original object) // this way we can control the testing environment and test the component in isolation. // It has the advantage of reducing the total number of dependencies of the unit. describe('03 - Pure Test - using a Stub object', () => { let authApiServiceStub: AuthApiService; let sut: AuthService; beforeEach(() => { // create a stub object, we can control the test implementing / changing its behavior on the fly. // we also have TypeScript to help us here (in case of refactoring). authApiServiceStub = <AuthApiService>{}; authApiServiceStub.login = (username: string, password: string) => Promise.resolve(true); sut = new AuthService(authApiServiceStub); }); app/unittests/00-pure-unit-tests/pure-tests-03-stub.spec.ts
  • 29. Jasmine: spy / spyOn // What if our system under test has some dependencies ? // Using the 'real services' is always a problem, we need to provide Test Doubles. // Provide a Stub, this way we can control the testing environment and // check the component in isolation. // Use Jasmine 'spyOn' to instrument and change the behavior of the real object. // We can also use it to check for expectations. describe('02 - Pure Test - spyOn - AuthApiService', () => { let authApiService: AuthApiService; let sut: AuthService; let loginSpy: jasmine.Spy; beforeEach(() => { authApiService = new AuthApiService(); sut = new AuthService(authApiService); // a spy can be used to provide canned return values to function calls. loginSpy = spyOn(authApiService, "login"); // .and.callThrough(); // instrument and delegate to the original function // .and.returnValue(false); // provide a return value, can also provide custom behavior with 'callFake' }); app/unittests/00-pure-unit-tests/pure-tests-02-spyOn.spec.ts
  • 30. Jasmine: spy / spyOn // Change behavior using a 'Spy' it("should have no logged user if login fails", async (done) => { // always fail the login procedure (this changes the service behavior) loginSpy.and.returnValue(false); const result = await sut.loginAsync("Alessandro", "12345"); expect(loginSpy.calls.count()).toBe(1); expect(result).toBeFalsy(); expect(sut.isLoggedIn).toBeFalsy(); expect(sut.username).toBe(""); done(); }); it("should have no logged user if the http call fails (fake)", async (done) => { // always fail the login procedure (this changes the service behavior) loginSpy.and.callFake((username: string, password: string) => { throw new Error("http error!") }); try { const result = await sut.loginAsync("Alessandro", "12345"); } catch (e) { expect((e as Error).message).toBe("http error!"); } expect(loginSpy.calls.count()).toBe(1); expect(sut.isLoggedIn).toBeFalsy(); expect(sut.username).toBe(""); done(); }); app/unittests/00-pure-unit-tests/pure-tests-02-spyOn.spec.ts
  • 31. Jasmine: stub & spy // Jasmine can also mix both approaches: // - create a stub object. // - augment it using a spy to trace the function calls. beforeEach(() => { // create a stub object, we can control the test implementing its behavior on the fly authApiServiceStub = <AuthApiService>{}; authApiServiceStub.login = (username: string, password: string) => Promise.resolve(true); loginSpy = spyOn(authApiServiceStub, "login"); sut = new AuthService(authApiServiceStub); }); app/unittests/00-pure-unit-tests/pure-tests-04-stub-spyOn.spec.ts
  • 32. Jasmine & Angular Utilities: async() // async() will call jasmine done() function for us when all the async operation // started in the async test zone complete themselves. it("(async()) should login a user", async(() => { sut.loginAsync("Alessandro", "12345") .then(result => { expect(result).toBeTruthy(); expect(sut.isLoggedIn).toBeTruthy(); expect(sut.username).toBe("Alessandro"); }); })); app/unittests/00-pure-unit-tests/pure-tests-05-async-testing-utilities.spec.ts done() will be called by Angular
  • 33. Jasmine & Angular Utilities: fakeAsync() // fakeAsync() + tick() allows us to write async tests in a more linear coding style: // the tests appear to be synchronous. // WARNING: cannot make XHR calls inside a fakeAsync zone! it("(fakeAsync(), no spyOn) should login a user", fakeAsync(() => { let result: boolean; sut.loginAsync("Alessandro", "12345") .then(res => result = res); // tick() simulates the asynchronous passage of time. tick(500); // the functions inside the async call have a 500 ms delay before completing expect(result).toBeTruthy(); expect(sut.isLoggedIn).toBeTruthy(); expect(sut.username).toBe("Alessandro"); })); There are still some problems with fakeAsync and async/await, setTimeout, setInterval, and some RxJS operators... app/unittests/00-pure-unit-tests/pure-tests-05-async-testing-utilities.spec.ts
  • 34. ‘Angular’ Unit Testing LET’S ENHANCE OUR TESTING EXPERIENCE!
  • 35. Angular Unit Testing What if we want to simulate the component as if it's part of a 'real' Angular application ? With the dependency injection, template rendering, bindings and DOM interactions? Introducing: TestBed and the Angular Testing Utilities!
  • 36. Angular Unit Testing Pros: •Extremely powerful. •Allows to test services and components (services, controllers, templates, bindings) in isolation. •Allows to test components and services interactions (@Input, @Output). Cons: •Take into account async operations since the start. •Need to consider the change detection mechanics (you must know how Angular works). •Tests initialization can be complex, you need to configure a fake ‘NgModule' with lots of moving parts. •Complex tests need a deep knowledge of Angular Testing Utilities and Test Doubles for components (Http, Router, …).
  • 37. TestBed - definition A testbed (also "test bed") is a platform for conducting rigorous, transparent, and replicable testing of scientific theories, computational tools, and new technologies. In software development testbedding is a method of testing a particular module (function, class, or library) in an isolated fashion. It may be used as a proof of concept or when a new module is tested apart from the program/system it will later be added to.
  • 38. TestBed & Angular Testing Utilities They are available importing: '@angular/core/testing'. TestBed is used to create an instance of a dynamically generated NgModule that will be configured to supply the system under test and all the needed Test Doubles (components, directives, service mocks, etc...). beforEach() test the whole module is resetted to the starting state.
  • 39. TestBed - API Use TestBed to configure a dynamically generated module environment: •.configureTestingModule() - takes a metadata object very close to the one used to define a real Angular module. The default testing module is configured with basic declaratives and some Angular service substitutes that every tester needs. •.compileComponents() - compile the testing module asynchronously. You must call this method if any of the testing module components have a templateUrl or styleUrls property. After calling compileComponents, the TestBed configuration is frozen for the duration of the current spec. •.createComponent() - create an instance of a component of type T. After calling compileComponent, the TestBed configuration is frozen for the duration of the current spec.
  • 40. Angular Stand-alone Testing Utilities Angular also provides some utility function that aim to simplify how tests are written. Some of the most used: •async() – runs the setup or the body of the test in a special async zone, ‘waiting’ for tasks to complete before moving to the next step. •fakeAsync() + tick() – runs the body of the test in a special fake async zone, allowing for a more linear control flow. •Inject() – injects services from the current TestBed instance. •By – an helper class whose methods are used to build query predicates. There are also many other functions that can be used to fine tune the tests (discardPeriodicTasks(), flushMicrotasks(), …).
  • 43. Angular Tests - setup describe('00 - Angular Tests - initialization - AppComponent', () => { // Jarmine runs the beforEach() function before each test to // reset the configuration of the testing TestBed NgModule before each test, it will provide you // with a clean environment every time. // You can have more than one beforeEach() in a test suite, they will be executed in the correct order. beforeEach(async(() => { // the component has external resources, and we need to give the compiler time to read them // the async() Angular test function will arrange the things so that the code is run in a special async test zone. // All the tests will be executed after any async operation started in the beforEach has been completed. // TestBed is used to define a dynamically generated NgModule. TestBed.configureTestingModule({ declarations: [ AppComponent ] }).compileComponents(); // calling 'compileComponents()' locks down the testing module. No more configuration // or override methods calls are allowed after this call. // If you don't call .compileComponents(), the first call to .createComponent() will // lock down the TestBed module too. // WebPack users do not need to call .compileComponents(), everything is inlined during the build phase. })); app/unittests/01-angular-testing/angular-tests-00-initialization.spec.ts
  • 44. ComponentFixture TestBed.createComponent() returns a 'ComponentFixture', a construct that gives access to: •componentInstance: a handle the component's controller. •debugElement: a handle to the component's DOM element.
  • 45. Angular Tests - ComponentFixture it('should create the app', () => { // use .createComponent() to get a ComponentFixture object. // A ComponentFixture is what you use to gain access to the component (componentInstance) const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; expect(app).toBeTruthy(); expect(app.title).toBe("app"); }); it("should not have any title in the DOM until Angular calls for change detection.", () => { // use .createComponent() to get a ComponentFixture object. // A ComponentFixture is what you use to gain access to the component DOM nodes (debugElement) const fixture = TestBed.createComponent(AppComponent); const compiled = fixture.debugElement.nativeElement; expect(compiled.querySelector('h1').textContent.trim()).toEqual("Welcome to"); }); app/unittests/01-angular-testing/angular-tests-00-initialization.spec.ts
  • 46. ChangeDetection By Design(tm) Angular testing framework does not trigger Change Detection automatically, you need to do that manually calling: ComponentFixture.detectChanges() •It gives us a chance to test the component in an uninitialized state, and check what happens to the template before and after the bindings did their magic. •It also means that: changing a property in the component as a synchronous operation will be invisible to Angular untill we call detectChanges() explicitly (even with the automatic detect changes in place). The default behavior can be changed setting: { provide: ComponentFixtureAutoDetect, useValue: true }
  • 47. Angulat Tests – detectChanges() // changeDetection() is not automatic, this is intentional, so the user // has a chance to inspect the component before Angular does its magic. // You can change this behavior configuring ComponentFixtureAutoDetect, like this: // { provide: ComponentFixtureAutoDetect, useValue: true } // The ComponentFixtureAutoDetect service responds to asynchronous activities such as promise resolution, // timers, and DOM events. it("should not have any title in the DOM until manually call 'detectChanged'", () => { const fixture = TestBed.createComponent(AppComponent); const compiled = fixture.debugElement.nativeElement; expect(compiled.querySelector('h1').textContent.trim()).toEqual("Welcome to"); }); it('should render title in a h1 tag', () => { const fixture = TestBed.createComponent(AppComponent); // ask Angular to apply its change detection cycle (all the bindings will be evaluated). // Angular responds to asynchronous activities such as promise resolution, timers, and DOM events. // WARNING!!! A direct, synchronous update of the component property is invisible. fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); }); app/unittests/01-angular-testing/angular-tests-01-detectChanges.spec.ts
  • 48. Component with Dependencies In order to control the environment we need to provide substitutes for the component dependencies. We can follow the same approaches we saw in the ‘Pure Tests’ scenarios: •Provide a Stub Object. •Spy on the Real Service. •Spy on a Stub Object. We’ll use dependency injection to supply services to our components!
  • 49. Component with Dependencies There’s one recommendation: if you need to interact with the injected services always get them from the component’s injector! (accessible through the ComponentFixture.debugElement.injector property). You can also get an instance of the service calling: •TestBed.get() •Inject()
  • 50. Angular Tests – stub object / D.I. // Always get the service from an Injector // do not reference this instance inside the tests anymore, the instance that will be // injected in the component is a clone - something different - of this object! describe('02 - Angular Tests - with dep. - GreetingsComponent - Stub Injected Service', () => { let component: GreetingsComponent; let fixture: ComponentFixture<GreetingsComponent>; // the stub definition object const authServiceStub = <AuthService>{ isLoggedIn: false }; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [GreetingsComponent], providers: [ { provide: AuthService, useValue: authServiceStub } ] }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(GreetingsComponent); component = fixture.componentInstance; // avoid calling the detectChanges() automatically, // we have a chance to interact with the services before the bindings are evaluated // fixture.detectChanges(); }); // Get the service from an injector! // 3 Ways to do it: // 1- from the Component's Injector // The way that will always work (angular has a ierarchy of injectors) is to ask the component's injector // (we can access it through the fixture). it("should access the injected service from the Component's Injector", () => { const auth = fixture.debugElement.injector.get(AuthService); expect(auth).not.toBeNull(); }); // 2- from TestBed.get() if the service is registered with the module it("should access the injected service from the TestBed.get()", () => { const auth = TestBed.get(AuthService); expect(auth).not.toBeNull(); }); // 3- using the inject() utility function if the service is registered with the module it("should access the injected service from the TestBed.get()", inject([AuthService], (auth) => { expect(auth).not.toBeNull(); }) ); app/unittests/01-angular-testing/angular-tests-02-component-withDep.spec.ts
  • 51. Angular Tests – async testing Always take into account the async nature of Angular (starting from how change detection works): •We can use the same techniques we saw in the ‘Pure Test’ scenarios. •Angular offers us async() and fakeAsync() standalone helper functions to make our life way easier writing tests. We already saw async() in action during the tests setup: beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [GreetingsAsyncComponent], providers: [AuthApiService, AuthService] }) .compileComponents(); })); app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
  • 52. … test setup context … beforeEach(() => { fixture = TestBed.createComponent(GreetingsAsyncComponent); component = fixture.componentInstance; authService = fixture.debugElement.injector.get(AuthService); // add a spy that provides the test with the proper initialization // we simulate having a user already authenticated, the server have to provide the // data. getLoggedUserAsyncSpy = spyOn(authService, "getLoggedUserAsync") .and.returnValue(Promise.resolve("Alessandro")); // .and.callThrough(); // delegating to functions with timers might create problems to Angular testing utilities el = fixture.debugElement.query(By.css("h3")).nativeElement; // will call this in the actual tests, to check for initialized state // fixture.detectChanges(); }); app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
  • 53. Angular Tests – async() // async() - Angular Testing Utility function it('should show greetings after getLoggedUserAsync promise (async)', async(() => { // force change detection, calls ngOnInit fixture.detectChanges(); // wait for the async function to complete (async test zone) fixture.whenStable() .then(() => { // force a change detection to update the view // (the tests does not do it automatically) fixture.detectChanges(); expect(el.textContent).toBe("welcome, Alessandro"); }); })); app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
  • 54. Angular Tests – fakeAsync() / tick() // fakeAsync() - Angular Testing Utility function // Enables a more linear coding style. // WARNING: cannot make XHR calls inside a fakeAsync() it('should show greetings after getLoggedUserAsync promise (fakeAsync)', fakeAsync(() => { // force change detection, calls ngOnInit fixture.detectChanges(); // wait for the async functions to complete (fake async zone) tick(); // use tick(500) when you set .and.callThrough() on the spy // force a change detection to update the view fixture.detectChanges(); expect(el.textContent).toBe("welcome, Alessandro"); })); app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
  • 55. Angular Tests – async ‘the jasmine way’ // sometimes we need to use the traditional jasmine way to do async tests // especially considering there may be problems with timers and xhr calls it('should show greetings after getLoggedUserAsync promise (jasmine)', done => { // force change detection, calls ngOnInit fixture.detectChanges(); // use the spy to be notified when the inner function call ends getLoggedUserAsyncSpy.calls.mostRecent().returnValue .then(() => { // force a change detection to update the view fixture.detectChanges(); expect(el.textContent).toBe("welcome, Alessandro"); done(); }); }); app/unittests/01-angular-testing/angular-tests-03-component-async.spec.ts
  • 56. Override Configuration Sometimes registering the providers with the test module is not enough, a component can define it's own dependency injection list, and we cannot directly stub the component's services in the dynamically generated test module (they are declared in the component metadata). What we can do is: override the component configuration and add, remove or set the metadata of the component: •TestBed.overrideComponent() •TestBed.overrideDirective() •TestBed.overrideModule() •TestBed.overridePipe() •TestBed.overrideTemplate() .overrideComponent(MyComponent, { set: { providers: [ { provide: Service, useClass: ServiceSpy} ] } }) .compileComponents();
  • 57. entryComponents: [] TestBed actually does not have a way to define the entryComponents metadata. Workaround: •Define a new NgModule declaring all the needed entryComponents. •Import the EntryComponents-NgModule in the TestBed.configureTestingModule() metadata.
  • 58. Test @Input and @Output Two strategies: •Test the component stand-alone, emulating the interaction with the rest of the world. Set the input properties and subscribe to the output properties (we have access to component’s controller through the ComponentFixture). •Create a Test Double (a very simple TestHostComponent), that can instantiate and use the component under test. Use the test double to drive the nested component and verify what happens (both in its controller and in its view).
  • 60. Code Coverage Code Coverage is a measure used to describe the degree to which the source code of a program is executed when a particular test suite runs. Angular CLI does the heavy lifting again and setup the code coverage analysis for us. Run the tests with: ng test --single-run=true --code-coverage You can configure the report output in the karma.config.js file.
  • 61. Application Lifecycle Management ADD THE TEST SUITE TO A CONTINOUS INTEGRATION TOOLS
  • 62. Integrate your build with VSTS Configure Karma for: •Single unit test execution. •Output unit test result in a parsable format. •Output code coverage information in a parsable format. Configure VSTS (other services behave differently) to: •On demand or Countinously build the application. •Get the source files, ‘npm install’ the packages and build the application. •Run the unit test suite. •Display the build / tests / code coverage results.
  • 63. Karma & Visual Studio Team Services Karma.config.js • Add a karma reporter plugin that can be parsed by VSTS: "karma-nunit2-reporter“. • Configure karma to report the unit test results in “nunit” format. • Configure Karma to output the code coverage analysis in “cobertura” format. module.exports = function (config) { config.set({ plugins: [ … require('karma-nunit2-reporter')], … coverageIstanbulReporter: { reports: [ 'html', 'lcovonly', 'cobertura' ], fixWebpackSourcePaths: true }, reporters: ['progress', 'kjhtml', 'nunit'], nunitReporter: { outputFile: 'test-results.xml', suite: '' }, … }); }; package.json: • Add the required plugin to emit the information in nunit format: • create a script to execute the tests and the code coverage analisys. • Test the script: “npm run vststest” { "name": "unit-tests", "scripts": { … "vststest": "ng test --single-run=true --code-coverage --reporters nunit" }, … "devDependencies": { … "karma-nunit2-reporter": "0.3.0", } }
  • 64. Configure VSTS to display the results
  • 65. Configure VSTS to display the results
  • 66. Configure VSTS to display the results
  • 67. Configure VSTS to display the results
  • 68. VSTS: the build report
  • 69.
  • 70. Thanks All! Q. & (maybe) A. !
  • 71. Who am I ? Dott.ing. Alessandro Giorgetti Facebook: https://www.facebook.com/giorgetti.alessandro Twitter: @a_giorgetti LinkedIn: https://it.linkedin.com/in/giorgettialessandro E-mail: alessandro.giorgetti@live.com Blog: www.primordialcode.com Alessandro Giorgetti www.primordialcode.com