We're Justin Dave @searls · 2015-05-01 · Have some side effect GET /hypothetical_feature Do...

Preview:

Citation preview

We're Justin & Dave (a.k.a @searls & @dmosher) Say hello@testdouble.com

testdouble/real-world-testing-video

go forth and github clone:

## background

## background

* ~~purposes of each type of test~~

## background

* ~~purposes of each type of test~~* ~~integration tests~~

## background

* ~~purposes of each type of test~~* ~~integration tests~~* ~~frameworks vs. TDD~~

## background

* ~~purposes of each type of test~~* ~~integration tests~~* ~~frameworks vs. TDD~~* a handful of situational tactics

## background

* ~~purposes of each type of test~~* ~~integration tests~~* ~~frameworks vs. TDD~~* a handful of situational tactics* using Jasmine

## background

* ~~purposes of each type of test~~* ~~integration tests~~* ~~frameworks vs. TDD~~* a handful of situational tactics* using Jasmine* generally applicable

## background

* ~~purposes of each type of test~~* ~~integration tests~~* ~~frameworks vs. TDD~~* a handful of situational tactics* using Jasmine* generally applicable

-ish

## background

* ~~purposes of each type of test~~* ~~integration tests~~* ~~frameworks vs. TDD~~* a handful of situational tactics* using Jasmine* generally applicable

-ish *ymmv*

## syntax

## syntax

### What we don't do

## syntax

### What we don't do

* use Jasmine's (RSpec-like) DSL

describe("Math", function(){ });

describe("Math", function(){ var subject, result; });

describe("Math", function(){ var subject, result; beforeEach(function(){ }); });

describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math(); }); });

describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math(); }); describe("#add", function(){ }); });

describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math(); }); describe("#add", function(){ beforeEach(function(){ }); }); });

describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math(); }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); }); });

describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math(); }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); it("adds", function(){ }); }); });

describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math(); }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); it("adds", function(){ expect(result).toEqual(9); }); }); });

## syntax

### What we don't do

* use Jasmine's (RSpec-like) DSL * test my JavaScript with JavaScript

## syntax

### What's the problem?

## syntax

### What's the problem?

* Jasmine DSL is not obvious

describe('thing', function(){});

describe('thing', function(){});

beforeEach(function(){});

describe('thing', function(){});

beforeEach(function(){});

afterEach(function(){});

describe('thing', function(){});

beforeEach(function(){});

afterEach(function(){});

it('does stuff', function(){});

describe('thing', function(){});

beforeEach(function(){});

afterEach(function(){});

it('does stuff', function(){});

expect(true).toBeTruthy();

describe('thing', function(){});

beforeEach(function(){});

afterEach(function(){});

it('does stuff', function(){});

expect(true).toBeTruthy();

this.addMatchers({});

describe('thing', function(){});

beforeEach(function(){});

afterEach(function(){});

it('does stuff', function(){});

expect(true).toBeTruthy();

this.addMatchers({});

jasmine.createSpy().andCallThrough();

## syntax

### What's the problem?

* Jasmine DSL is not obvious * test code can be verbose, unwieldy

... expect(spec).toFinallyEnd(); }); }); }); }); }); });

## syntax

### What's the problem?

* Jasmine DSL is not obvious * test code can be verbose, unwieldy * those crying mustaches

## syntax

### What's the problem?

* Jasmine DSL is not obvious * test code can be verbose, unwieldy * those crying mustaches });

## syntax

### What we do

## syntax

### What we do

* write specs in CoffeeScript

describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math(); }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); it("adds", function(){ expect(result).toEqual(9); }); }); });

describe "Math", -> beforeEach -> @subject = new Math()

describe "#add", -> beforeEach -> @result = @subject.add(4,5)

it "adds", -> expect(@result).toEqual(9)

CoffeeScript basics*

CoffeeScript basics*

*Fear not, it's just JS.

var add = function(a,b) { return a + b; };

add = (a,b) -> a + b

this.save();

@save()

var self = this; save(function(){ self.display("Yay!"); });

save => @display("Yay!")

## syntax

### What we do

* write specs in CoffeeScript * use the *-given DSL

describe "Math", -> beforeEach -> @subject = new Math()

describe "#add", -> beforeEach -> @result = @subject.add(4,5)

it "adds", -> expect(@result).toEqual(9)

describe "Math", -> Given -> @subject = new Math()

describe "#add", -> When -> @result = @subject.add(4,5) Then -> @result == 9

describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math(); }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); it("adds", function(){ expect(result).toEqual(9); }); }); });

describe "Math", -> Given -> @subject = new Math()

describe "#add", -> When -> @result = @subject.add(4,5) Then -> @result == 9

## syntax

### What we do

* write specs in CoffeeScript * use the *-given DSL * jasmine-given is a port of rspec-given

## syntax

### What we do

* write specs in CoffeeScript * use the *-given DSL * jasmine-given is a port of rspec-given * mocha-given is a port of jasmine-given

## syntax

### What we do

* write specs in CoffeeScript * use the *-given DSL * jasmine-given is a port of rspec-given * mocha-given is a port of jasmine-given * mocha-gwt is a rewrite of mocha-given

demo

Roman Numerals

1-standalone

how'd that go?

break

discovery testing

Discovery Tests

</>

I ❤ test doubles

I ❤ mocks

I 💔 other people's mocks

Hypothetical feature:

Hypothetical feature:

• Generate a random arithmetic problem (e.g. 5+3)

Hypothetical feature:

• Generate a random arithmetic problem (e.g. 5+3)

• Store it so that a subsequent request can find it

Hypothetical feature:

• Generate a random arithmetic problem (e.g. 5+3)

• Store it so that a subsequent request can find it

• Accept attempted solutions to problems and respond

{

{ id: 1,

{ id: 1, operands: {

{ id: 1, operands: { left: 5,

{ id: 1, operands: { left: 5, right: 8

{ id: 1, operands: { left: 5, right: 8 },

{ id: 1, operands: { left: 5, right: 8 }, operator: '+',

{ id: 1, operands: { left: 5, right: 8 }, operator: '+', description: '5 * 8'

{ id: 1, operands: { left: 5, right: 8 }, operator: '+', description: '5 * 8'}

{ id: 1, operands: { left: 5, right: 8 }, operator: '+', description: '5 * 8'}

{ id: 1, operands: { left: 5, right: 8 }, operator: '+', description: '5 * 8'}

{ id: 1, operands: { left: 5, right: 8 }, operator: '+', description: '5 * 8'}

GET /problemGets

Random Problem

Generates Random Problem

GET /problemGets

Random Problem

Generates Random Problem

GET /problemGets

Random Problem

Saves Problem

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

let's play

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

Focus

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

Leaf Nodes

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

No mocks, only logic!

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

Collaborators

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

No logic, only mocks!

Generates Random Problem

Describes Problem

GET /problemGets

Random Problem

Saves Problem

Gives Random Character

Gives Random Integer

too many things! cognitive overhead!

units so small they're disposable

Responding to changing requirements:

Have some side effect

GET /hypothetical_featureDo hard thing

Transform stuff

Query for stuff

Join Things

Build query

Filter Results

Contact Server

Paginate Stuff

Fetch stuff

Have some side effect

GET /hypothetical_featureDo hard thing

Transform stuff

Query for stuff

Join Things

Build query

Filter Results

Contact Server

Paginate Stuff

Fetch stuff1. Identify smallest sub-tree

affected by change

Have some side effect

GET /hypothetical_featureDo hard thing

Transform stuff

Query for stuff

Join Things

Build query

Filter Results

Contact Server

Paginate Stuff

Fetch stuff1. Identify smallest sub-tree

affected by change

Have some side effect

GET /hypothetical_featureDo hard thing

Transform stuff

Query for stuff

Join Things

Build query

Filter Results

Contact Server

Paginate Stuff

Fetch stuff1. Identify smallest sub-tree

affected by change

2. Delete sub-tree if change is non-trivial

Have some side effect

GET /hypothetical_featureDo hard thing

Transform stuff

Query for stuff

Join Things

Build query

Filter Results

1. Identify smallest sub-tree affected by change

2. Delete sub-tree if change is non-trivial

Have some side effect

GET /hypothetical_featureDo hard thing

Transform stuff

Query for stuff

Join Things

Build query

Filter Results

1. Identify smallest sub-tree affected by change

2. Delete sub-tree if change is non-trivial

3. Drive out a new solution

Have some side effect

GET /hypothetical_featureDo hard thing

Transform stuff

Query for stuff

Join Things

Build query

Filter Results

1. Identify smallest sub-tree affected by change

2. Delete sub-tree if change is non-trivial

3. Drive out a new solutionContact Server

Paginate better

Fetch stuff better

Have some side effect

GET /hypothetical_featureDo hard thing

Transform stuff

Query for stuff

Join Things

Build query

Filter Results

1. Identify smallest sub-tree affected by change

2. Delete sub-tree if change is non-trivial

3. Drive out a new solution

4. Pay technical debt by trusting future-us to know better

Contact Server

Paginate better

Fetch stuff better

Changing code is hard.

Changing code is hard.big

Changing code is hard.

Changing code is hard.long

Changing code is hard.

Changing code is hard.old

Changing code is hard.

Changing code is hard.ALL

Changing code is hard.

Consider a workflow that disposes, rather than changes, existing code

2-node

{

{ operator: '+',

{ operator: '+', operands: {

{ operator: '+', operands: { left: 84,

{ operator: '+', operands: { left: 84, right: 92

{ operator: '+', operands: { left: 84, right: 92 },

{ operator: '+', operands: { left: 84, right: 92 }, description: '84 + 92',

{ operator: '+', operands: { left: 84, right: 92 }, description: '84 + 92', id: 9222

{ operator: '+', operands: { left: 84, right: 92 }, description: '84 + 92', id: 9222}

GET /problem

GET /problemGET /problem/:id

GET /problemGET /problem/:idPOST /solution

3-lineman

## Lineman

Get up and running in minutes!

* [Docs](http://linemanjs.com)

4-testium

Recommended