Slide 1

Slide 1 text

Unit Testing In Angular Wednesday April 4, 2018 Doug Corbett [email protected]

Slide 2

Slide 2 text

What is Unit Testing and Why Should I Care? 1 Let’s Try it Out 3 Final Thoughts 4 Anatomy of an Angular Unit Test 2 Agenda

Slide 3

Slide 3 text

on What is Unit Testing and Why Should I Care?

Slide 4

Slide 4 text

Unit Tests • Tests designed to prove software functionality works according to client specification.

Slide 5

Slide 5 text

Unit Test Characteristics • Functionality tested is small and isolated per test. • Can be automated.

Slide 6

Slide 6 text

One Extreme – The Purist “Unit Test everything or you are just a hack” * https://www.fjackets.com/buy/Sherlock-Holmes-Coat.html

Slide 7

Slide 7 text

Another Extreme “I don’t always test my code, but when I do – I do it in production” * https://legendsbeard.com/b/bearded-legend-chuck-norris/ http://www.xento.com/blog/unit-testing-and-its-importance-2/

Slide 8

Slide 8 text

Case For Implementing Unit Tests * https://programmingwithmosh.com/csharp/unit-testing/ • Manual regression testing is error-prone, time consuming and often not thorough despite the best intentions • Unit testing is pretty easy to do. • Unit testing provides self documenting code. • Unit testing is fast and as thorough as you make it. • TDD allows you to write tests that clearly describes business intent • No one knows the code as well as the developers

Slide 9

Slide 9 text

Case Against Implementing Unit Tests * https://programmingwithmosh.com/csharp/unit-testing/ • Seems like a waste of time. • Some developers think testing is beneath them. • Eyeballing test results during development is sufficient • Not enough time to test every permutation, so why do any. • Current team doesn’t use unit tests.

Slide 10

Slide 10 text

So When do I Recommend Unit Tests? On projects where there is business logic or validation. So yeah … All projects The key is to keep the tests small and test paths that are particularly complicated or error prone.

Slide 11

Slide 11 text

Testing Breakout 5% 25% 70% End-to-end Integration Testing Unit Testing

Slide 12

Slide 12 text

Common Testing Frameworks

Slide 13

Slide 13 text

Common Testing Frameworks

Slide 14

Slide 14 text

on Anatomy of an Angular Unit Test

Slide 15

Slide 15 text

Arrange, Act, Assert Set up the test scenario Do the work Test the results aka Given, When, Then

Slide 16

Slide 16 text

Jasmine Keywords and Concepts • describe - means of organizing tests • it - start of a test • xit - skip test • expect - assertions • toBe - matcher describe("A suite", function() { it("contains spec with an expectation", function() { expect(true).toBe(true); }); });

Slide 17

Slide 17 text

Jasmine – Other Matchers expect(true).toBe(true); expect(false).not.toBe(true); expect(a).toEqual(12); expect(message).toMatch(/bar/); expect(message).toMatch("bar"); expect(a.foo).toBeDefined(); expect(a.bar).toBeUndefined() expect(a).toBeNull() expect(foo).toBeTruthy(); expect(a).toBeFalsy(); expect(a).toContain("bar") expect(e).toBeLessThan(pi); expect(pi).toBeGreaterThan(e); expect(pi).toBeCloseTo(e, 0); expect(bar).toThrow(); expect(foo).toThrowError("foo bar baz"); expect(foo).toThrowError(/bar/);

Slide 18

Slide 18 text

Jasmine Life Cycle Methods • beforeEach() • beforeAll() • afterEach() • afterAll() beforeEach(function() { // do some setup before each test }); afterEach(function() { // do some cleanup after each test });

Slide 19

Slide 19 text

Unit Test Concepts • Stubs – can substitute a class method or property with itself • Mocks – A full blown class with the same signature as a class it is intended to replace. • Spies – a type of mock that can simulate return values and count the number of times a method was call and with which parameters. Relies on SpyObject

Slide 20

Slide 20 text

Stubs describe(“transfer", function() { it(“should return true when from account has sufficient funds", function() { // arrange let customerRepository = { getAccount: function(string accountNumber) { if (accountNumber == 1) { return { “accountNumber”: accountNumber, balance: 302.23 }; if (accountNumber == 2) { return { “accountNumber”: accountNumber, balance: 743.90 }; return null; } }; let bankService: BankService = new BankService(customerRepository); string fromAcct = ‘544325667’; string toAcct = ‘123123123’; decimal transferAmount = 100; // act let result = bankService.Transfer(fromAcct, toAcct, transferAmount); // assert expect(result).toBe(true); }); });

Slide 21

Slide 21 text

Mocks class MockCustomerRepository: ICustomerRepository { public getAccount(string accountNumber) { if (accountNumber == 1) { return { “accountNumber”: accountNumber, balance: 302.23 }; } if (accountNumber == 2) { return { “accountNumber”: accountNumber, balance: 743.90 }; return null; } public getTop10Customers() { … } public requestBackgroundCheck(string customerID) { … } } describe(“transfer", function() { it(“should return true when from account has sufficient funds", function() { // arrange let customerRepository = new MockCustomerRepository(); let bankService: BankService = new BankService(customerRepository); string fromAcct = ‘544325667’; string toAcct = ‘123123123’; decimal transferAmount = 100; // act let result = bankService.Transfer(fromAcct, toAcct, transferAmount); // assert expect(result).toBe(true); }); });

Slide 22

Slide 22 text

Spies describe(“transfer", function() { it(“should call getAccount twice when transferring funds", function() { // arrange let repo = new CustomerRepository(); let spy = spyOn(repo, ‘getAccount’).and.returnValue( new Account() {“accountNumber”: ‘544325667’, “balance”: 3432.98 }); let bankService: BankService = new BankService(repo); string fromAcct = ‘544325667’; string toAcct = ‘123123123’; decimal transferAmount = 100; // act let result = bankService.Transfer(fromAcct, toAcct, transferAmount); // assert expect(spy).toHaveBeenCalledTimes(2); }); });

Slide 23

Slide 23 text

Spies 2 describe(“transfer", function() { it(“should call getAccount twice when transferring funds", function() { // arrange let repo= new CustomerRepositorySpy(); let bankService: BankService = new BankService(spy); string fromAcct = ‘544325667’; string toAcct = ‘123123123’; decimal transferAmount = 100; // act let result = bankService.Transfer(fromAcct, toAcct, transferAmount); // assert expect(spy.getAccountSpy).toHaveBeenCalledTimes(2); }); }); import { SpyObject } from ‘./test.helpers’; import {CustomerRepository } from ‘./customer.repository’; export class CustomerRepositorySpy: ICustomerRepository extends SpyObject { getAccountSpy; constructor() { super(CustomerRepository); this.getAccountSpy = this.spy(‘getAccount’).and.returnValue new Account() {“accountNumber”: ‘544325667’, “balance”: 3432.98 }); } getProviders(): Array { return [{ provide: CustomerRepository, useValue: this }]; } }

Slide 24

Slide 24 text

on Let’s Try It Out

Slide 25

Slide 25 text

Scenario The IRS called and they want you to build a web page to help citizens donate their hard earned money to fund government projects. They call it ez1040.gov. Some of the website is complete, we need you to do the following. 1. Create a tax service that takes a taxable amount and returns the tax owed or a refund amount with unit tests. (basic flow) 2. Create a SSN validator service that takes a name and ssn and calls a third party web service with unit tests. (stub, mock and Mock backend) 3. Make sure that when a user changes the taxable amount twice it triggers a call to getJointTax twice and getSingleTax zero times. (spy)

Slide 26

Slide 26 text

1040 EZ

Slide 27

Slide 27 text

Demo

Slide 28

Slide 28 text

on Code Coverage

Slide 29

Slide 29 text

Code Coverage $ ng test –code-coverage Creates new folder “coverage”, from there open up index.html

Slide 30

Slide 30 text

Final Thoughts

Slide 31

Slide 31 text

Final Thoughts

Slide 32

Slide 32 text

Reference Materials Official Angular Documentation https://angular.io Jasmine Github Repo https://jasmine.github.io/ Karma Github Repo https://karma-runner.github.io ng-book – The Complete Book on Angular 4 – Nathan Murray and Ari Lerner Angular Unit Test Demo code