1 of 42

The Benefits of

Testing and Automation

@ataylorme • Slides: goo.gl/s1eMNn

2 of 42

Hi, I’m Andrew

Developer Programs Engineer at Pantheon.

ataylorme on GitHub and Twitter.

andrew@pantheon.io

Some things I enjoy away from the computer are

  • Running, weight lifting, basketball
  • Mountain biking, hiking, off roading, camping
  • Craft beer and good food

@ataylorme • Slides: goo.gl/s1eMNn

3 of 42

Adding Tests To "Catch of The Day"

@ataylorme • Slides: goo.gl/s1eMNn

4 of 42

The Price Input Experience

@ataylorme • Slides: goo.gl/s1eMNn

5 of 42

Order.js

const total = orderIds.reduce((prevTotal, key) => {

const fish = this.props.fishes[key];

const count = this.props.order[key];

const isAvailable = fish && fish.status === "available";

if (isAvailable) {

return prevTotal + count * fish.price;

}

return prevTotal;

}, 0);

@ataylorme • Slides: goo.gl/s1eMNn

6 of 42

helpers.js

export function formatPrice(cents) {

return (cents / 100).toLocaleString("en-US", {

style: "currency",

currency: "USD"

});

}

@ataylorme • Slides: goo.gl/s1eMNn

7 of 42

Read The Docs

@ataylorme • Slides: goo.gl/s1eMNn

8 of 42

Add formatPrice.test.js

import { formatPrice } from "../helpers";

test('formatPrice returns a properly formatted price', () => {

const priceList = [

[123456,'$1,234.56',],

[1234567890,'$12,345,678.90',],

['12345.67889.986545','$12,345,678,899,865.45',],

[-12345678.91,'-$12,345,678.91',],

['1234@$975645643asfasdf.w3rw.sdfdzc4','$1,234,975,645,643.34',],

];

priceList.forEach(function (prices) {

expect(formatPrice(prices[0])).toBe(prices[1]);

});

});

@ataylorme • Slides: goo.gl/s1eMNn

9 of 42

Run The Test

@ataylorme • Slides: goo.gl/s1eMNn

10 of 42

Add toCents function helpers.js

export function toCents(input) {

let cents = input

// convert to a string

.toString()

// remove everything except numbers and dashes

.replace(/[^\d-]/g, "");

// convert back to a number

cents = parseInt(cents, 10);

return cents;

}

@ataylorme • Slides: goo.gl/s1eMNn

11 of 42

helpers.js

export function formatPrice(input) {

if( null === input ){

return '';

}

const cents = toCents(input);

// format for US dollars

return (cents / 100).toLocaleString("en-US", {

style: "currency",

currency: "USD"

});

}

@ataylorme • Slides: goo.gl/s1eMNn

12 of 42

Order.js

const total = orderIds.reduce((prevTotal, key) => {

const fish = this.props.fishes[key];

const count = this.props.order[key];

const isAvailable = fish && fish.status === "available";

if (isAvailable) {

return prevTotal + (count * toCents(fish.price));

}

return prevTotal;

}, 0);

@ataylorme • Slides: goo.gl/s1eMNn

13 of 42

Test Again

@ataylorme • Slides: goo.gl/s1eMNn

14 of 42

Refactored Price Input Experience

@ataylorme • Slides: goo.gl/s1eMNn

15 of 42

Add toCents Test

import { toCents } from "../helpers";�test('toCents returns the cents value of different inputs', () => {

const priceList = [

[123456,123456,],

['12345.67889.986545',1234567889986545,],

[-12345678.91,-1234567891,],

['1234@$975645643asfasdf.w3rw.sdfdzc4',123497564564334,],

];

priceList.forEach(function (prices) {

expect(toCents(prices[0])).toBe(prices[1]);

});

});

@ataylorme • Slides: goo.gl/s1eMNn

16 of 42

Run The Tests Automatically With CI

@ataylorme • Slides: goo.gl/s1eMNn

17 of 42

What is Continuous Integration?

LoopConf 3.0 • Slides: goo.gl/YB3v43

18 of 42

It is a State of Mind

LoopConf 3.0 • Slides: goo.gl/YB3v43

19 of 42

What Happens After �a Code Change?

LoopConf 3.0 • Slides: goo.gl/YB3v43

20 of 42

  • Install Dependencies
  • Build source files
  • Deployment
  • Communication
  • Testing / Q.A.
  • Configuration Import

Let the robots do all the things

Devs do custom work, �robots do redundant tasks

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

21 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

22 of 42

Consistency

@ataylorme • Slides: goo.gl/s1eMNn

23 of 42

Ever Forgotten To Check That One Thing After a Deploy?

@ataylorme • Slides: goo.gl/s1eMNn

24 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

25 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

26 of 42

Reduced Overhead

@ataylorme • Slides: goo.gl/s1eMNn

27 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

28 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

29 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

30 of 42

Risk Mitigation

@ataylorme • Slides: goo.gl/s1eMNn

31 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

32 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

33 of 42

Confidence

@ataylorme • Slides: goo.gl/s1eMNn

34 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

35 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

36 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

37 of 42

Communication

@ataylorme • Slides: goo.gl/s1eMNn

38 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

39 of 42

@ataylorme • Slides: goo.gl/s1eMNn

@ataylorme • Slides: goo.gl/s1eMNn

40 of 42

Automation is a journey

@ataylorme • Slides: goo.gl/s1eMNn

41 of 42

Resources

@ataylorme • Slides: goo.gl/s1eMNn

42 of 42

Thanks!

Slides: goo.gl/s1eMNn

@ataylorme

@ataylorme • Slides: goo.gl/s1eMNn