R\2 Pt Pl a aN
Introduction to Testing Angular
Applications
Key objectives of this chapter
= Angular testing technologies and setup
= Jasmine unit test basics
= Angular TestBed and test configuration
= Testing a service
= Testing a component
1.1 Unit Testing Angular Artifacts
= Just like any other development project, it is important to test Angular
applications. This includes:
© Manual unit testing during development
¢ Automated unit testing. This will be the focus of this chapter.
« Manual quality assurance testing by professional testers
= Angular applications are modular so with the right tools and techniques it
is possible to perform robust unit/integration testing
= You are encouraged to write unit test scripts and run them after major
changes to the codebase.
= Unit tests should also be run after a build to verify the build
Canada United States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Pl
11866 206 4644
[email protected] 1877 517 6540 9
Jenkintown, PA. 19046 1
[email protected]Rg WEB AGE SOLUTIONS INC
1.2 Testing Tools
= Jasmine - The Jasmine test framework is for testing JavaScript code
« Jasmine is probably the most important tool used, besides Angular
itself, as the unit tests themselves are written according to Jasmine
= Karma - Helps simplify running Jasmine tests although it can also work
with other frameworks
¢ Karma is a Node.js tool and requires Node.js and npm installed
« You can run your Jasmine specifications (test scripts) in multiple
browsers like Firefox and Chrome
¢ Karma will automatically watch all JavaScript files and re-run the tests if
any one of them is modified
= Protractor - Simulate user activities on a browser for “end to end” testing
° This chapter will not focus on Protractor as there is not as much low-
level integration required as with Jasmine
a Angular testing utilities - Angular provides AP! and tools to write unit
tests.
Testing Tools
With Jasmine tests, you can generate an HTML "test runner" to run in a browser without Karma.
Karma can automatically generate this for running tests and run the tests in a browser automatically, so
Karma simplifies the testing process.
‘The main focus of this chapter is the Angular testing utilities and integration with Jasmine tests.
Protractor testing is less Angular-specific and does not require the Angular testing utilities.
Jasmine — https:/fjasmine.github io!
Karma — https://github.comy/karma-rumer/karma,
Protractor — http://www. protractortest.org
Canada Unit
d States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Place, Jenkintown, PA. 19046 2
11866 206 4644
[email protected] 1877 517 6540
[email protected]Rg Py lee e re Ne
1.3 Testing Setup
= Create a regular project to set it up for testing.
ng new simple-app
= That does these things:
¢ It adds Karma and Jasmine dependencies in package json
« Generates the Karma config file karma.conf,js.
¢ Itconfigures .angular-cli.json file so that a test script file is created by
Angular CLI with every new component, service etc.
= Aminimal project created using --minimal flag does not have support for
testing. Do not use it for real projects.
= By default, Karma is configured to use the Chrome browser which must be
installed
Testing Setup
This chapter will focus on using the Angular project setup (or "quickstart") to setup for testing although
Angular CLI setup should be similar.
The details of some of the configuration files above are not provided but can be found in the
documentation of the relevant framework. This slide is mainly to be familiar with some of the files
important in setting up testing.
There is also a ‘protractor.config.js' file for Protractor configuration although that is not covered here.
Karma can integrate with other frameworks besides Jasmine but the Angular testing configuration uses
this combination.
Canada
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Place, Jenkintown, PA. 19046 3
11866 206 4644
[email protected] 1877 517 6540
[email protected]Rg Pt Pl a aN
1.4 Typical Testing Steps
= Define test scripts. Angular CLI creates a file ending in '.spec.ts' for a
generated component, service etc. Example:
banner.component.ts is tested by banner.component.spec.ts
= You can create additional test scripts. Just give them a '.spec.ts'
extension.
= Run the 'npm test’ or 'ng test’ command to run the tests. This will:
e Doabuild
¢ Run all test scripts in the project.
« Show the test result along with the application in a browser.
= Examine the test output for any test failures
= Ifyou change your code the tests will be run again and the browser will be
updated with the new test results
= End testing by hitting Control+C. This will also close the test browser.
Canada United States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Pl
11866 206 4644
[email protected] 1877 517 6540 9
Jenkintown, PA. 19046 4
[email protected]Rg WEB AGE SOLUTIONS INC
1.5 Test Results
Chrome 64.0.3282 (Mac OS X 10.13.3) is idle
Jasmine 2.8.0
eoxeccece
eee cra
Spec List | Failures
eee eT
Failed: Cannot read property ‘textContent’ of null
TypeError: Cannot read property 'textContent' of null
at UserContext.
Chttp://localhost :9876/_karma_we
at ZoneDelegate.webpackJsonp.../../../../zone. js/dist/zone.
= Shows a green dot for each successful test and a red X for failed test.
= For each failed test the name of the test and a stack trace is shown
Canada
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Place, Jenkintown, PA. 19046 5
11866 206 4644 [email protected] 1877 517 6540 [email protected]1.6 Jasmine Test Suites
= Atest suite in Jasmine is defined with the describe function, which takes
two parameters:
« Astring, which acts as a title (it is displayed on the spec runner page).
A function that implements the test suite:
describe("Test Suite #1", function() {
//.. . unit tests (specs) or other describe functions
We
= A test suite acts as a container for:
¢ Actual unit tests
° Other test suites
= So, you may have a hierarchy of nested test suites.
= Usually you write one test suite in each spec.ts file.
Canada United States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Pl
11866 206 4644 [email protected] 1877 517 6540 got
intown, PA. 19045 6
[email protected]Rg Pt Pl a aN
1.7 Jasmine Specs (Unit Tests)
= In Jasmine, a unit test is referred to as a spec.
= Specs are defined by the it function which takes two parameters:
« Astring, which acts as a title (it is displayed on the spec runner page
facilitating the behavior-driven development).
A function that implements the actual unit test.
= Variables declared in the parent describe function (the test suite container)
are visible in the unit tests (it function(s)
= Aspec is a container for one or more expectations (assertions) about the
code outcome (pass/fail).
describe('Simple test suite’, () => {
it("Test addition", () => {
expect (1+2) . toBe (3)
H)
})
Canada United States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Place, Jenkintown, PA. 19046 7
11866 206 4644 [email protected] 1877 517 6540 [email protected]1.8 Expectations (Assertions)
= Expectations are defined by the expect function that performs an
assertion on the expected value of a variable or a function passed to the
expect function as a parameter.
¢ The expect function's parameter is called the actual.
= An expectation is evaluated to either true or false.
¢ An expectation evaluated to true is treated as test success (test
passed).
° A false result is treated as a failed unit test.
= The expect function is chained with a matcher function, which takes the
expected value.
= Example:
expect () .toBe ();
where toBe is a matcher function chained to the expect function via the dot-
notation.
= Note: You can also chain other matchers.
Canada United States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Pl
11866 206 4644 [email protected] 1877 517 6540 got
intown, PA. 19045 8
[email protected]Rg Py lee e re Ne
1.9 Matchers
= Amatcher is a function that performs a boolean comparison between the
actual value (passed to the chained expect function) and the expected
value (passed as a parameter to the matcher).
= Jasmine comes with a rich catalog of built-in matchers:
toBe toBeUndefined
toBeCloseTo toContain
toBeDefined tokqual
toBeFalsy toHaveBeenCalled
toBeGreaterThan toHaveBeenCalledWith
toBeLessThan toMatch
toBeNaN toThrow
toBeNull toThrowError
toBeTruthy
= Developers can also create their own (custom) matchers.
Matchers
toBe compares using the triple equal sign:
toE-qual works for simple literals and variables
toMateh is used for regular expressions
toBeDefined and toBeUndefined compare against undefined
toBeNull compares against null
toBeTruthy checks for true
toBeFalsy checks for false
toContain is used for finding an element in an Array
toBeLessThan is used for mathematical '"
Canada United States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Place, Jenkintown, PA. 19046 9
11866 206 4644 [email protected] 1877 517 6540 [email protected]Rg Py lee e re Ne
toBeCloseTo is used for precision math comparison
toThrow is used for testing if a function throws an exception
1.10 Examples of Using Matchers
= Here is a full example of a spec used to test a simple function
it ("Test #234", function (){
var testFunction = function () {
return 1000 + 1;
i
expect (testFunction()) .toEqual (1001) ;
Ye
« Note: The testFunction function would normally be placed in a separate
JavaScript file of functions to be tested.
= Similarly, you can test a variable.
= Note: The expect function performs an expression evaluation, so you can
assert math expressions as well, e.g.
expect (1000 + 1) .toEqual (1001);
Canada
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Place, Jenkintown, PA. 19046 10
11866 206 4644 [email protected] 1877 517 6540 [email protected]Rg Pt Pl a aN
1.11 Using the not Property
= To reverse the expected value (e.g. from false to true), matchers are
chained to the expect function via the not property.
= For example, the following assertions are functionally equivalent:
expect () .toBe (true);
expect () .not.toBe (false) ;
1.12 Setup and Teardown in Unit Test Suites
a Jasmine lets you write functions that are called before and after each spec
(test). They are registered using beforeEach() and afterEach().
= The beforeEach function runs the common initialization code (if needed).
= The afterEach function contains the clean up code (if needed).
= Both functions take a function as a parameter.
= You can have multiple beforeEach() and afterEach() functions.
Canada United States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Pl
Jenkintown, PA. 19046 “
11866 206 4644 [email protected] 1877 517 6540 9
[email protected]Rg WEB AGE SOLUTIONS INC
1.13 Example of beforeEach and afterEach Functions
describe("A Test suite with setup and teardown", function () {
var obj = (}i
beforeEach(function() {
obj.propl = true;
// obj.fooBar - undefined !
We
afterEach(function() {
obj = (he
ve
it("has one property, for sure", function() {
expect (obj.propl).toBeTruthy(); // is true, indeed
ve
it("has undefined property", function() (
expect (obj. fooBar) . toBeUndefined () 7
ve
ve
Example of beforeEach and afterEach Functions
None of the code above is specific to Angular. This just shows the Jasmine-related code and the
structure of a Jasmine test.
Canada Unit
d States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Place, Jenkintown, PA. 19046 2
11866 206 4644 [email protected] 1877 517 6540 [email protected]1.14 Angular Test Module
= Every test suite needs to define an Angular module.
= Tests are run using this module and not the real application module. This
is necessary so that you can use mock services during testing.
= The item under test and all of its dependencies must be added as
providers, declarations, and imports of that module.
= Atest module is created using the configureTestingModule() method of
the TestBed class.
1.15 Example Angular Test Module
import { TestBed, inject } from '@angular/core/testing';
import { HttpClientModule } from '@angular/common/http';
import { BlogService } from './blog.service';
describe ('BlogService', () => {
beforeEach(() => {
TestBed.configureTestingModule ({
imports: [HttpClientModule],
providers: [BlogService]
Ye
de
‘fy
}
= Here we are testing BlogService which depends on HitpClient. Our test
module had to be set up for that to work.
Canada United States
821A Bloor Street West, Toronto, Ontario, MEG M1744 Yorkway Pl
11866 206 4644 [email protected] 1877 517 6540 got
intown, PA. 19045 B
[email protected]Rg WEB AGE SOLUTIONS INC
1.16 Testing a Service
= Services are easier to test than components. This should encourage you
to write more test scripts for services.
= We will test this service.
export class BlogService {
constructor (private http:HttpClient) { }
sayHello(name:string) : string {
return ‘Hello ${name}*
}
getBlogPost (postId:number) : Observable