80
UI Testing, handling complex UIs at scale Josh Black :: FEDucation :: March 2nd, 2016 . FED@IBM

UI Testing

Embed Size (px)

Citation preview

Page 1: UI Testing

UI Testing, handling complex UIs at scale

Josh Black :: FEDucation :: March 2nd, 2016

.FED@IBM

Page 2: UI Testing

Discussion Time A look at the landscape of testing options and techniques for developers.

.FED@IBM

Page 3: UI Testing

Wikipedia An investigation conducted to provide information about the quality of a product or service under test.

.FED@IBM

Page 4: UI Testing

TestingHelps developers tell whether the product is working or not.

.FED@IBM

Page 5: UI Testing

OverviewThe Basics What are the various kinds of tests? How do I know when to use each one?

Writing a Test How can we structure our tests in a way that's clean, readable, and effective?

Real World What kind of tools can I leverage to start testing in my project today?

Page 6: UI Testing

0Part 0 Setting the Stage

What is a test?

.FED@IBM

Page 7: UI Testing

Testing When a developer changes a piece of code in a project, how confident am I that sh*t won't break?

.FED@IBM

Page 8: UI Testing

Testing a Dropdown

class Dropdown { /* ... */ }

const d = new Dropdown({ items: ['Home', 'Cognitive', 'Watson', 'Services'], defaultText: 'Please select an item', target: document.querySelector('.dropdown') });

.FED@IBM

Page 9: UI Testing

HTML

<ul class="dropdown"> <li class="dropdown__item"> <p id="current">Please select an item</p> <span class="dropdown__arrow"></span> <ul class="dropdown-menu"> <li class="dropdown-menu__item"><a href="#">Home</a></li> <li class="dropdown-menu__item"><a href="#cognitive">Cognitive</a></li> <li class="dropdown-menu__item"><a href="#watson">Watson</a></li> <li class="dropdown-menu__item"><a href="#services">Services</a></li> </ul> </li> </ul>

.FED@IBM

Page 10: UI Testing

JavaScript

const d = new Dropdown({ items: ['Home', 'Cognitive', 'Watson', 'Services'], defaultText: 'Please select an item', target: document.querySelector('.dropdown') });

dropdown.arrow.addEventListener('click', () => { dropdown.classList.toggle('is-expanded'); });

.FED@IBM

Page 11: UI Testing
Page 12: UI Testing

.FED@IBM

Page 13: UI Testing

.FED@IBM

Page 14: UI Testing
Page 15: UI Testing

Testing Allows us to make a trade-off between reliability and speed.

.FED@IBM

Page 16: UI Testing

Testing a Dropdown

class Dropdown { /* ... */ }

const d = new Dropdown({ items: ['Home', 'Cognitive', 'Watson', 'Services'], defaultText: 'Please select an item', target: document.querySelector('.dropdown') });

.FED@IBM

Page 17: UI Testing

Testing a Dropdown

describe('Dropdown', () => { it('should ...', () => { // ... }); });

.FED@IBM

Page 18: UI Testing

Testing a Dropdown

describe('Dropdown', () => { it('should expand the list of options when clicked', () => { // ... }); });

.FED@IBM

Page 19: UI Testing

Testing a Dropdown

describe('Dropdown', () => { it('should expand the list of options when clicked', () => { // ... });

it('should collapse the list of options when an item is selected', () => { // ... }); });

.FED@IBM

Page 20: UI Testing

Test-Driven Development

Page 21: UI Testing

Test Behavior-Driven Development

Page 22: UI Testing

Add some initial, failing tests

Add Tests

.FED@IBM

Page 23: UI Testing

Write an initial attempt at making your test pass

Write code

.FED@IBM

Page 24: UI Testing

Run tests, re-working until they go green

Run Tests

.FED@IBM

Page 25: UI Testing

Now that you have passing tests, go back and refine

Refactor

.FED@IBM

Page 26: UI Testing

Unit Tests

Allows us to test small pieces of functionality in isolation.

Integration Tests

End-to-End Tests

Understand and test how a user flows through the system

Test the integration of small pieces of functionality with each other

Testing Basic Types

.FED@IBM

Page 27: UI Testing

Unit Tests

const addIntegers = (a, b) => a + b;

describe('add', () => { it('should add two integers together', () => { const a = 1; const b = 2;

expect(add(a, b)).toBe(a + b); // true || false }); });

.FED@IBM

Page 28: UI Testing

Unit Tests

const addIntegers = (a, b) => a + b;

addIntegers(1.5, 'a'); // 1.5a

.FED@IBM

Page 29: UI Testing

Unit Tests

const addIntegers = (a, b) => { const { isInteger } = Number;

invariant( isInteger(a) && isInteger(b), 'Expected integer arguments, instead got: [%s, %s]', a, b );

return a + b; }

.FED@IBM

Page 30: UI Testing

Unit Tests

const addIntegers = (a, b) => /* ... */

describe('add', () => { it('should warn if an argument is not an integer', () => { const a = 1; const b = 'a';

expect(add(a, b)).toThrow(); }); });

.FED@IBM

Page 31: UI Testing

Integration Tests

Page 32: UI Testing

Scenario

.FED@IBM

Visualization

API Response Validation

Duration

Count Visualization

Page 33: UI Testing

Scenario

.FED@IBM

Validation

Duration

Count

Page 34: UI Testing

Scenario

.FED@IBM

Validation

Duration

Count

Page 35: UI Testing

Testing a Validator

describe('Validator', () => { it('should validate a response from our API', () => { // ... }); });

.FED@IBM

Page 36: UI Testing

Testing getDuration

describe('getDuration', () => { it('should get a duration value from an API response', () => { // ... }); });

.FED@IBM

Page 37: UI Testing

Integration Test

import Validator from '../Validator'; import getDuration from '../getDuration';

describe('getResponseDuration', () => { it('should get a duration value from an API response', () => { const response = {}; const validated = Validator(response);

expect(validated.passed).toBe(true); expect(validated.value).toBe(response.result.data);

// ... }); });

.FED@IBM

Page 38: UI Testing

Integration Test

describe('getResponseDuration', () => { it('should get a duration value from an API response', () => { const response = {}; const validated = Validator(response);

expect(validated.passed).toBe(true); expect(validated.value).toBe(response.result.data);

const durationCount = getDuration(validated.value); expect(durationCount).toBe(300); }); });

.FED@IBM

Page 39: UI Testing

End-to-End Tests

Page 40: UI Testing

E2E Focus on real user scenarios, catching bugs before they reach the user.

.FED@IBM

Page 41: UI Testing

E2E Scenario

.FED@IBM

Hits EnterLogin Form Clicks Form Enter Credentials

Page 42: UI Testing

Testing Pyramid

.FED@IBM

E2E

Integration

Unit

Page 43: UI Testing

Testing Pyramid

.FED@IBM

E2E

Integration

Unit

Unit Testing

Allows us to create a fast, reliable feedback loop that isolates errors.

Requirements: Knowledge in areas such as dependency management, mocking, and hermetic testing.

Page 44: UI Testing

Testing Pyramid

.FED@IBM

E2E

Integration

Unit

Integration Tests

Allows us to verify the behavior of small groups of units

Page 45: UI Testing

Testing Pyramid

.FED@IBM

E2E

Integration

Unit

End-to-End Tests

Covers a small set of our product features to help catch bugs that may reach customers

Page 46: UI Testing

Take a Look Just Say No More to End-to-End Tests Covers the practicality of E2E tests, highlighting the advantages of favoring unit/integration tests over E2E.

Move Fast and Don't Break Things Discusses the integration and role of testing in the context of Continuous Integration and Delivery

Link

Link

Page 47: UI Testing

1Part 1 Writing a test

.FED@IBM

How to actually get started

Page 48: UI Testing

Setup Test runners, assertions, and spies, oh my!

.FED@IBM

mocha

chai

karma

expect

expect.js

jasmine

sinon

qunitselenium

web driver

ava

jsdom

Page 49: UI Testing

.FED@IBM

Page 50: UI Testing

Test Runner

Allows us to write chunks of code to describe what should happen. Handles executing tests for us and returning the result.

Assertion Library

Spies

Sometimes we need to check and verify that what we think will be called is actually called

Enables us to state what we believe to be true, false, and a variety of other states.

Testing Checklist

.FED@IBM

Page 51: UI Testing

Test Runner

Allows us to write chunks of code to describe what should happen. Handles executing tests for us and returning the result.

Assertion Library

Spies

Sometimes we need to check and verify that what we think will be called is actually called

Enables us to state what we believe to be true, false, and a variety of other states.

Testing Checklist

.FED@IBM

DOM Mocking / Driver

Allows us to verify that what we expect to happen in our product is actually happening

Page 52: UI Testing

Test Runner

describe('Module', () => { it('should ...', () => { // ... }); });

.FED@IBM

Page 53: UI Testing

Test Runner

.FED@IBM

Page 54: UI Testing

Take a Look Mocha Classic JavaScript test framework for JavaScript

Jasmine DOM-less simple JavaScript Testing Framework

https://www.npmjs.com/package/mocha

https://www.npmjs.com/package/jasmine

Karma Spectacular Test Runner for JavaScript https://www.npmjs.com/package/karma

Ava Futuristic Test Runner for JavaScript https://www.npmjs.com/package/ava

Page 55: UI Testing

Assertions

Page 56: UI Testing

Assertions Specify what you expect the outcome of a scenario to be.

.FED@IBM

Page 57: UI Testing

Assertions

describe('Module', () => { it('should ...', () => { const result = Module();

expect(result).toBe(2); }); });

.FED@IBM

Page 58: UI Testing

Assertions

describe('Module', () => { it('should ...', () => { const result = Module();

expect(result).toEqual({ title: 'FEDucation', description: 'Coolest FED gathering in the world' }); }); });

.FED@IBM

Page 59: UI Testing

Assertions

describe('Module', () => { it('should ...', () => { const result = Module();

expect(result).toEqual(['some', 'collection']); }); });

.FED@IBM

Page 60: UI Testing

Assertions

describe('Module', () => { it('should ...', () => { const result = Module();

expect(result).toThrow(); }); });

.FED@IBM

Page 61: UI Testing

Assertions

describe('Module', () => { it('should ...', () => { const result = Module();

expect(result).to.be.instanceOf(Error); }); });

.FED@IBM

Page 62: UI Testing

Assertions

it('supports loading multiple keys in one call', async () => { var identityLoader = new DataLoader(keys => Promise.resolve(keys));

var promiseAll = identityLoader.loadMany([ 1, 2 ]); expect(promiseAll).to.be.instanceof(Promise);

var values = await promiseAll; expect(values).to.deep.equal([ 1, 2 ]);

var promiseEmpty = identityLoader.loadMany([]); expect(promiseEmpty).to.be.instanceof(Promise);

var empty = await promiseEmpty; expect(empty).to.deep.equal([]); });

.FED@IBM

Page 63: UI Testing

Take a Look Expect Write better assertions

Chai BDD/TDD assertion library for node.js and the browser

https://www.npmjs.com/package/expect

https://www.npmjs.com/package/chai

Should Test framework agnostic BDD-style assertions https://www.npmjs.com/package/should

Assert Native assertion library for Node.js

Page 64: UI Testing

Spies

Page 65: UI Testing

Spies Stubs out any function and tracks calls to it and all arguments

.FED@IBM

Page 66: UI Testing

Assertions

const sum = (a, b) => a + b;

describe('A spy', () => { it('should track that the spy was called', () => { spyOn(sum); sum(1, 2); expect(sum).toHaveBeenCalled(); expect(sum).toHaveBeenCalledWith(1, 2); }); });

.FED@IBM

Page 67: UI Testing

Assertions

describe('Module', () => { it('should track that the spy was called', () => { spyOn(console, 'error'); const result = Module('invalid argument'); expect(console.error).toHaveBeenCalled(); expect(console.error) .toHaveBeenCalledWith('invalid argument'); }); });

.FED@IBM

Page 68: UI Testing

Isolation

Achieves similar results to mocks, stubs, dummies, fakes, etc for accomplishing isolation

Consistent Interface

Partial Mocking

You as the developer choose what portions of an interface you want to mock

Spies follow the same interface as the functions that they're mocking

SpiesHighlights

.FED@IBM

Page 69: UI Testing

Take a Look Jasmine DOM-less simple JavaScript Testing Framework

Expect Write better assertions

Sinon JavaScript test spies, stubs and mockshttps://www.npmjs.com/package/sinon

Page 70: UI Testing

DOM Mocking

Page 71: UI Testing

End-to-End Tests

Prohibitively Expensive Loading up the browser, and performing a multitude of tests doesn't fit our ideal feedback loop for testing.

Flakiness Race conditions, or other processes that may yield inconsistent results for a test due to using the DOM.

Tooling In the past, we'd have to use complex tool chains like Selenium with Web Driver just to get E2E that don't actually help us, or the user.

Page 72: UI Testing

Take a Look jsdom A JavaScript implementation of the DOM and HTMl standards

Karma Brings a productive testing environment to developers

https://www.npmjs.com/package/jsdom

https://www.npmjs.com/package/karma

Selenium Web Driver Driving a browser natively as a user would http://docs.seleniumhq.org/projects/webdriver/

Page 73: UI Testing

DOM Mocking

import jsdom from 'mocha-jsdom'; import { expect } from 'chai';

describe('mocha tests', function () { jsdom()

it('has document', function () { var div = document.createElement('div') expect(div.nodeName).eql('DIV') }); });

.FED@IBM

Page 74: UI Testing

DOM Mocking

it('should work for DOM events', function () { var div = document.createElement('div'); div.addEventListener('click', () => console.log('FEDs rule!'));

spyOn(console, 'log');

div.click();

expect(console.log).toHaveBeenCalled(); expect(console.log).toHaveBeenCalledWith('FEDs rule!'); });

.FED@IBM

Page 75: UI Testing

DOM Mocking

import jsdom from 'mocha-jsdom'; import { expect } from 'chai';

const markup = '<html>...</html>';

describe('mocha tests', function () { jsdom(markup)

it('has document', function () { var app = document.querySelector('#app') expect(app.nodeName).eql('DIV') }); });

.FED@IBM

Page 76: UI Testing

Recap The Basics Overview of Unit, Integration, and End-to-End tests.

The Tools Identify the necessary components that developers need for a robust testing framework.

The Practice How do we go about structuring our tests, and begin writing tests using the techniques/testing frameworks that we've identified0

Page 77: UI Testing

Google Focus on the user and all else will follow

.FED@IBM

Page 78: UI Testing

Testing Enables us to move fast and not break things

.FED@IBM

Page 79: UI Testing

@joshblackfr github.com/joshblack

github.ibm.com/joshblack

Page 80: UI Testing

Thanks! Any Questions?