how to express your requirements as tests, and vice versa johannes brodwall

76
How to express your requirements as tests, and vice versa Johannes Brodwall

Upload: amari-cutting

Post on 01-Apr-2015

224 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: How to express your requirements as tests, and vice versa Johannes Brodwall

How to express your requirements as tests, and vice versaJohannes Brodwall

Page 2: How to express your requirements as tests, and vice versa Johannes Brodwall

Understanding the problemJohannes Brodwall

Page 3: How to express your requirements as tests, and vice versa Johannes Brodwall

How to express your requirements as tests, and vice versaJohannes Brodwall

Page 4: How to express your requirements as tests, and vice versa Johannes Brodwall

FitNesse eksempel #1

Page 5: How to express your requirements as tests, and vice versa Johannes Brodwall

FitNesse eksempel #1

Page 6: How to express your requirements as tests, and vice versa Johannes Brodwall

Understanding the problemJohannes Brodwall

Chief Scientist, Steria

Page 7: How to express your requirements as tests, and vice versa Johannes Brodwall

Background: What’s a requirement?

Page 8: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep9 © Steria

”Why does the customer

want a solution?”

Page 9: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep10 © Steria

Understanding the need

Page 10: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep11 © Steria

Tools:

•Vision statements

•User analysis

Page 11: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep12 © Steria

”What do we implement

when?”

Page 12: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep13 © Steria

Planning

Page 13: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep14 © Steria

Tools:

•Product backlog

•User stories

Page 14: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep15 © Steria

”How should the

functionality work?”

Page 15: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep16 © Steria

Requirement specification

Page 16: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep17 © Steria

Tools:

•Acceptance tests

Page 17: How to express your requirements as tests, and vice versa Johannes Brodwall

Tests emerge from discussions

Page 18: How to express your requirements as tests, and vice versa Johannes Brodwall

Example: Electronic signature

Page 19: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep20 © Steria

Developer

Product owner

Tester

Page 20: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep21 © Steria

Developer

Product owner

Tester

Page 21: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep22 © Steria

Developer

Product owner

Tester

As a payment issuer,I want to sign my payments,So that nobody can impersonate me

Page 22: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep23 © Steria

Developer

Product owner

Tester

What about a file that contains both signed and failed payments?

Page 23: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep24 © Steria

Developer

Product owner

Tester

Ummm......(help?)

Page 24: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Page 25: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep26 © Steria

Developer

Product owner

Tester

Given ....When ....Then ...

Page 26: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep27 © Steria

Developer

Product owner

Tester

Given a file with payment 1 and payment 2And payment 1 is signed correctlyAnd payment 2 is signed incorrectlyWhen the file is validatedThen payment 1 should be processed as usualAnd the payment issuer should receive a receipt indicating payment 2 was rejected

Page 27: How to express your requirements as tests, and vice versa Johannes Brodwall

An anonymized example from a real project

Page 28: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

FitNesse eksempel #1

Page 29: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Page 30: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep31 © Steria

Developer

Product owner

Tester

Given ....When ....Then ...

Page 31: How to express your requirements as tests, and vice versa Johannes Brodwall

A practical example

Page 32: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep33 © Steria

Developer

Product owner

Tester

Given ....When ....Then ...

Cucumber(rspec)

Page 33: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

From my current project:Feature: ”Assign task to me”

Given I go to the work task screen ”team tasks”And I pick the first task with ”SSN” equal ”11111111”And I press the button ”Take task”When I go to the work task screen ”my tasks”Then the work task list should contain 1 taskAnd the ”SSN” of the task should be ”1111111”

Page 34: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Executed automatically

Given I go to the work task screen ”team tasks”And I pick the first task with ”SSN” equal ”11111111”And I press the button ”Take task”When I go to the work task screen ”my tasks”Then the work task list should contain 1 taskAnd the ”SSN” of the task should be ”1111111”

Page 35: How to express your requirements as tests, and vice versa Johannes Brodwall

Fictive example: Yahtzee

Page 36: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep37 © Steria

Developer

Product owner

Tester

Full house should give 25 point

Page 37: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Page 38: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep39 © Steria

Developer

Product owner

Tester

Full house should give 25 point

Page 39: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep40 © Steria

Developer

Product owner

Tester

Is it a full house if five die_values all have the same pipcount?

Page 40: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep41 © Steria

Developer

Product owner

Tester

WTF?!?

Page 41: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Page 42: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep43 © Steria

Developer

Product owner

Tester

For example five dice all reading 1 is not full house

Ok!

Page 43: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Page 44: How to express your requirements as tests, and vice versa Johannes Brodwall

Acceptance tests communicate requirements

Page 45: How to express your requirements as tests, and vice versa Johannes Brodwall

Developers tests

Page 46: How to express your requirements as tests, and vice versa Johannes Brodwall

Reflect functional tests

Page 47: How to express your requirements as tests, and vice versa Johannes Brodwall

Should express requirements (but smaller)

Page 48: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit example: Repository

@Testpublic void shouldRetrieveSameInstanceForSameKey() throws Exception { Category inserted = new Category("A"); Serializable id = repository.insert(inserted); repository.flushChanges();

Category retrieved1 = repository.retrieve(Category.class, id); Category retrieved2 = repository.retrieve(Category.class, id); Category retrieved3 = repository.find(Category.class).iterator().next(); retrieved1.setCategoryName("Z"); assertEquals(retrieved1.getCategoryName(), retrieved2.getCategoryName()); assertEquals(retrieved1.getCategoryName(), retrieved3.getCategoryName());}

Page 49: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

@Testpublic void shouldRetrieveSameInstanceForSameKey() throws Exception { Category inserted = new Category("A"); Serializable id = repository.insert(inserted); repository.flushChanges();

Category retrieved1 = repository.retrieve(Category.class, id); Category retrieved2 = repository.retrieve(Category.class, id); Category retrieved3 = repository.find(Category.class).iterator().next(); retrieved1.setCategoryName("Z"); assertEquals(retrieved1.getCategoryName(), retrieved2.getCategoryName()); assertEquals(retrieved1.getCategoryName(), retrieved3.getCategoryName());}

JUnit: Repository

When I modify one of the retrieved instances

Then the others should be updated, too

Given a database with one object

Given I retrieve this object several times

Page 50: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Repository

@Testpublic void uncommittedInsertsShouldBeInvisibleForOtherThreads() { repository.beginTransaction(); Category category = new Category("A"); repository.insert(category); repository.flushChanges();

assertNull(retrieveInNewThread(Category.class, category.getId()));

repository.commit(); assertEquals(category, retrieveInNewThread(Category.class, category.getId()));}

Page 51: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Repository

@Testpublic void uncommittedInsertsShouldBeInvisibleForOtherThreads() { repository.beginTransaction(); Category category = new Category("A"); repository.insert(category); repository.flushChanges();

assertNull(retrieveInNewThread(Category.class, category.getId()));

repository.commit(); assertEquals(category, retrieveInNewThread(Category.class, category.getId()));}

Given I insert a new object while in a transaction

When I retrieve the object from another thread

Then I should not be able to see it

When I commit the transactionWhen I retrieve the object from another threadThen I should be able to see it

Page 52: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Repository

@Testpublic void uncommittedInsertsShouldBeInvisibleForOtherThreads() { repository.beginTransaction(); Category category = new Category("A"); repository.insert(category); repository.flushChanges();

assertNull(retrieveInNewThread(Category.class, category.getId()));

repository.commit(); assertEquals(category, retrieveInNewThread(Category.class, category.getId()));}

Given I insert a new object while in a transaction

When I retrieve the object from another thread

Then I should not be able to see it

When I commit the transactionWhen I retrieve the object from another threadThen I should be able to see it

Uncommitted Inserts Should

Be Invisible For Other

Threads

Page 53: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Web tests

@Testpublic void listProductsPageShouldShowAll() throws Exception { Product product1 = new Product(uniqueName("product"), 12300); Product product2 = new Product(uniqueName("product"), 300); repository.insertAll(product1, product2); repository.flushChanges();

tester.beginAt("/products/"); tester.assertTextInElement("products", product1.getProductName()); tester.assertTextInElement("products", product2.getProductName());}

Page 54: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Web tests

@Testpublic void listProductsPageShouldShowAll() throws Exception { Product product1 = new Product(uniqueName("product"), 12300); Product product2 = new Product(uniqueName("product"), 300); repository.insertAll(product1, product2); repository.flushChanges();

tester.beginAt("/products/"); tester.assertTextInElement("products", product1.getProductName()); tester.assertTextInElement("products", product2.getProductName());}

Then I should see both products

Given two products with unique names in the database

When I go to the /products/ web page

Page 55: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit : Negative tests

@Test

public void priceMustBeNumeric() throws Exception {

String oldName = uniqueName("product"); int oldPrice = 1234;

Product product = new Product(oldName, oldPrice); Serializable id = repository.insert(product); repository.flushChanges();

tester.beginAt("/products/" + id + "/edit.html"); tester.setTextField("productName", uniqueName("product")); tester.setTextField("price", "this is not a price!"); tester.submit();

tester.assertMatchInElement("errorExplaination", "[Pp]rice .*numeric");

Product stored = repository.retrieve(Product.class, id); assertEquals(oldPrice, stored.getPrice()); assertEquals(oldName, stored.getProductName());}

Page 56: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Negative tests

@Testpublic void priceMustBeNumeric() throws Exception { String oldName = uniqueName("product"); int oldPrice = 1234;

Product product = new Product(oldName, oldPrice); Serializable id = repository.insert(product); repository.flushChanges();

tester.beginAt("/products/" + id + "/edit.html"); tester.setTextField("productName", uniqueName("product")); tester.setTextField("price", "this is not a price!"); tester.submit();

tester.assertMatchInElement("errorExplaination", "[Pp]rice .*numeric");

Product stored = repository.retrieve(Product.class, id); assertEquals(oldPrice, stored.getPrice()); assertEquals(oldName, stored.getProductName());}

Then I should see an error message

Given a product in the database

When I go to the /products/<id>/edit web pageAnd I go change the price to a negative valueAnd I press submit

And the product should be unchanged in the database

Page 57: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep58 © Steria

Developer

Given ....When ....Then ...

Page 58: How to express your requirements as tests, and vice versa Johannes Brodwall

Good design can be grown

Page 59: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Yahtzee histogram

@Test public void simpleCategoriesShouldBeSumOfMatchingDice() { ... }

@Test public void smallStrait() { ... }

@Test public void largeStrait() { ... }

@Test public void threeOfAKind() { ... }

Page 60: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Yahtzee histogram

@Test public void threeOfAKind() {

assertEquals(0, scoreFor("three_of_a_kind", 1, 1, 2, 2, 3));

assertEquals(3, scoreFor("three_of_a_kind", 1, 1, 1, 2, 3));

assertEquals(6, scoreFor("three_of_a_kind", 2, 2, 2, 3, 3));

assertEquals(9, scoreFor("three_of_a_kind", 1, 1, 3, 3, 3));

}

Page 61: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Yahtzee histogram

@Test public void fullHouse() {

assertEquals(0, scoreFor("full_house", 1, 1, 2, 2, 3));

assertEquals(0, scoreFor("full_house", 1, 1, 1, 2, 3));

assertEquals(25, scoreFor("full_house", 1, 1, 1, 2, 2));

assertEquals(25, scoreFor("full_house", 1, 1, 2, 2, 2));

assertEquals(25, scoreFor("full_house", 5, 5, 6, 6, 6));

}

Page 62: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Yahtzee histogram

@Test public void histogramShouldReturnFrequencyOfEachDie() {

int[] roll = { 1, 1, 2, 3, 4 };

int[] histogram = new ScoreCard().histogram(roll);

assertEquals(7, histogram.length);

assertEquals(-1, histogram[0]);

assertEquals(2, histogram[1]);

assertEquals(1, histogram[2]);

assertEquals(1, histogram[3]);

assertEquals(1, histogram[4]);

assertEquals(0, histogram[5]);

assertEquals(0, histogram[6]);

Page 63: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

JUnit: Yahtzee histogram

scoreCalculators.put("four_of_a_kind", new ScoreCalculator() {

@Override

public int calculate(int[] histogram) {

for (int i=0; i<histogram.length; i++) {

if (histogram[i] >= 4) return i*4;

}

return 0;

}

});

Page 64: How to express your requirements as tests, and vice versa Johannes Brodwall

Testing: Costs and benefits

Page 65: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep66 © Steria

Ron Jeffries

Only test what you want to work

Page 66: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep67 © Steria

Johannes

Find the defect where it’s cheapest

Page 67: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Unscientific graph!

Compiler Junit FitNesse System test Prod

Cost

Realism

Page 68: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Unscientific graph!

Compiler Junit FitNesse System test Prod

Cost

Realism

Chance of finding defects

Page 69: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Unscientific graph!

Compiler Junit FitNesse System test Prod

Cost

Realism

Cost of running and changing

tests

Page 70: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria

Unscientific graph!

Compiler Junit FitNesse System test Prod

Cost

Realism

Cost of a defect

Page 71: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep72 © Steria

Johannes

Unit tests can reduce maintaince costs. (How?)

Page 72: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep73 © Steria

Johannes

When will unit tests increase maintainance cost?

Page 73: How to express your requirements as tests, and vice versa Johannes Brodwall

© Steria| 11/04/23 Presentation titlep74 © Steria

Brian Marick

Automated tests are expensive to maintainIf the system wasn’t written to be tested

Page 74: How to express your requirements as tests, and vice versa Johannes Brodwall

But maintainability is only one reason to test!

Page 75: How to express your requirements as tests, and vice versa Johannes Brodwall

How to create a good solution?

Page 76: How to express your requirements as tests, and vice versa Johannes Brodwall

Understand the problem