testing - v4.software-carpentry.org · nobody enjoys testing so you can skip this lecture if –...

71
Introduction Testing Introduction Copyright © Software Carpentry 2010 This work is licensed under the Creative Commons Attribution License See http://software-carpentry.org/license.html for more information.

Upload: others

Post on 26-Mar-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Introduction

Testing

Introduction

Copyright © Software Carpentry 2010

This work is licensed under the Creative Commons Attribution License

See http://software-carpentry.org/license.html for more information.

Page 2: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Nobody enjoys testing

Testing Introduction

Page 3: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Nobody enjoys testing

So you can skip this lecture if

Testing Introduction

Page 4: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Nobody enjoys testing

So you can skip this lecture if

– your programs always work correctly, or– your programs always work correctly, or

Testing Introduction

Page 5: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Nobody enjoys testing

So you can skip this lecture if

– your programs always work correctly, or– your programs always work correctly, or

– you don't care if they're correct or not, so long

as their output looks plausible, and

Testing Introduction

Page 6: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Nobody enjoys testing

So you can skip this lecture if

– your programs always work correctly, or– your programs always work correctly, or

– you don't care if they're correct or not, so long

as their output looks plausible, and

– you like being inefficient

Testing Introduction

Page 7: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Nobody enjoys testing

So you can skip this lecture if

– your programs always work correctly, or– your programs always work correctly, or

– you don't care if they're correct or not, so long

as their output looks plausible, and

– you like being inefficient

The more you invest in quality, the less total time

Testing Introduction

The more you invest in quality, the less total time

it takes to build working software

Page 8: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing tells you:

Testing Introduction

Page 9: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing tells you:

– if the program is doing what it's supposed to

Testing Introduction

Page 10: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing tells you:

– if the program is doing what it's supposed to

– what the program actually is supposed to do– what the program actually is supposed to do

Testing Introduction

Page 11: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing tells you:

– if the program is doing what it's supposed to

– what the program actually is supposed to do– what the program actually is supposed to do

Tests are runnable specifications

Testing Introduction

Page 12: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing tells you:

– if the program is doing what it's supposed to

– what the program actually is supposed to do– what the program actually is supposed to do

Tests are runnable specifications

– Less likely to fall out of sync with the program

than documentation

Testing Introduction

Page 13: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Quality is not just testing

Testing Introduction

Page 14: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Quality is not just testing

Trying to improve the quality of software by

doing more testing is like trying to lose weightdoing more testing is like trying to lose weight

by weighing yourself more often.

– Steve McConnell

Testing Introduction

Page 15: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Quality is not just testing

Trying to improve the quality of software by

doing more testing is like trying to lose weightdoing more testing is like trying to lose weight

by weighing yourself more often.

– Steve McConnell

Good tests localize problems to speed up debugging

Testing Introduction

Page 16: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing comparison of 7-digit phone numbers

Testing Introduction

Page 17: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing comparison of 7-digit phone numbers

107 possible numbers

Testing Introduction

Page 18: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing comparison of 7-digit phone numbers

107 possible numbers

(107)2 possible pairs of numbers(107)2 possible pairs of numbers

Testing Introduction

Page 19: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing comparison of 7-digit phone numbers

107 possible numbers

(107)2 possible pairs of numbers(107)2 possible pairs of numbers

At 106 million tests/sec, that's 155 days

Testing Introduction

Page 20: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Testing comparison of 7-digit phone numbers

107 possible numbers

(107)2 possible pairs of numbers(107)2 possible pairs of numbers

At 106 million tests/sec, that's 155 days

...and then you start testing the next function

Testing Introduction

Page 21: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

How do you know that your tests are correct?

Testing Introduction

Page 22: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

"All" testing can do is show that

there might be a problem

Testing Introduction

Page 23: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

"It might work in practice,

but it'll never work in theory."

Testing Introduction

Page 24: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

If testing isn't easy, people won't do it

Testing Introduction

Page 25: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

If testing isn't easy, people won't do it

Must be easy to:

Testing Introduction

Page 26: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

If testing isn't easy, people won't do it

Must be easy to:

– add or change tests– add or change tests

Testing Introduction

Page 27: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

If testing isn't easy, people won't do it

Must be easy to:

– add or change tests– add or change tests

– understand existing tests

Testing Introduction

Page 28: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

If testing isn't easy, people won't do it

Must be easy to:

– add or change tests– add or change tests

– understand existing tests

– run tests

Testing Introduction

Page 29: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

If testing isn't easy, people won't do it

Must be easy to:

– add or change tests– add or change tests

– understand existing tests

– run tests

– understand test results

Testing Introduction

Page 30: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

If testing isn't easy, people won't do it

Must be easy to:

– add or change tests– add or change tests

– understand existing tests

– run tests

– understand test results

And test results must be reliable

Testing Introduction

And test results must be reliable

Page 31: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

If testing isn't easy, people won't do it

Must be easy to:

– add or change tests– add or change tests

– understand existing tests

– run tests

– understand test results

And test results must be reliable

Testing Introduction

And test results must be reliable

– No false positives or false negatives

Page 32: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

A unit test tests one component in a program

Testing Introduction

Page 33: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

Testing Introduction

Page 34: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

What the test

is run onis run on

Testing Introduction

Page 35: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

action

Testing Introduction

Page 36: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

actionWhat's done to

the fixture

Testing Introduction

Page 37: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

action

expected result

Testing Introduction

Page 38: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

action

expected resultWhat should

happen

Testing Introduction

Page 39: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

action

expected result

actual result

Testing Introduction

actual result

Page 40: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

action

expected result

actual resultWhat actually

Testing Introduction

actual resultWhat actually

happened

Page 41: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

action

expected result

actual result

Testing Introduction

actual result

report

Page 42: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

fixture

A unit test tests one component in a program

action

expected result

actual result

Testing Introduction

actual result

report Summary

Page 43: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Test dna_starts_with

Testing Introduction

Page 44: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Test dna_starts_with

True if second argument is a prefix of the first

Testing Introduction

Page 45: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Test dna_starts_with

True if second argument is a prefix of the first

False otherwiseFalse otherwise

Testing Introduction

Page 46: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Test dna_starts_with

True if second argument is a prefix of the first

False otherwiseFalse otherwise

dna_starts_with('actggt', 'act') => True

Testing Introduction

Page 47: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Test dna_starts_with

True if second argument is a prefix of the first

False otherwiseFalse otherwise

dna_starts_with('actggt', 'act') => True

dna_starts_with('actggt', 'ctg') => False

Testing Introduction

Page 48: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Test dna_starts_with

True if second argument is a prefix of the first

False otherwiseFalse otherwise

dna_starts_with('actggt', 'act') => True

dna_starts_with('actggt', 'agt') => False

Do this one from scratch to show ideas

Testing Introduction

Page 49: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

Test dna_starts_with

True if second argument is a prefix of the first

False otherwiseFalse otherwise

dna_starts_with('actggt', 'act') => True

dna_starts_with('actggt', 'agt') => False

Do this one from scratch to show ideas

Then introduce a library that can take care of

Testing Introduction

Then introduce a library that can take care of

the repetitive bits

Page 50: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Test directly

assertassertassertassert dna_starts_with('a', 'a')

assertassertassertassert dna_starts_with('at', 'a')

assertassertassertassert dna_starts_with('at', 'at')assertassertassertassert dna_starts_with('at', 'at')

assertassertassertassert notnotnotnot dna_starts_with('at', 't')

Testing Introduction

Page 51: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Test directly

assertassertassertassert dna_starts_with('a', 'a')

assertassertassertassert dna_starts_with('at', 'a')

assertassertassertassert dna_starts_with('at', 'at')assertassertassertassert dna_starts_with('at', 'at')

assertassertassertassert notnotnotnot dna_starts_with('at', 't')

This works...

Testing Introduction

Page 52: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Test directly

assertassertassertassert dna_starts_with('a', 'a')

assertassertassertassert dna_starts_with('at', 'a')

assertassertassertassert dna_starts_with('at', 'at')

This works...

...but there's a lot of repeated code...

assertassertassertassert dna_starts_with('at', 'at')

assertassertassertassert notnotnotnot dna_starts_with('at', 't')

Testing Introduction

Page 53: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Test directly

assertassertassertassert dna_starts_with('a', 'a')

assertassertassertassert dna_starts_with('at', 'a')

assertassertassertassert dna_starts_with('at', 'at')

This works...

...but there's a lot of repeated code...

...and it's easy to overlook that not...

assertassertassertassert dna_starts_with('at', 'at')

assertassertassertassert notnotnotnot dna_starts_with('at', 't')

Testing Introduction

...and it's easy to overlook that not...

Page 54: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Test directly

assertassertassertassert dna_starts_with('a', 'a')

assertassertassertassert dna_starts_with('at', 'a')

assertassertassertassert dna_starts_with('at', 'at')

This works...

...but there's a lot of repeated code...

...and it's easy to overlook that not...

assertassertassertassert dna_starts_with('at', 'at')

assertassertassertassert notnotnotnot dna_starts_with('at', 't')

Testing Introduction

...and it's easy to overlook that not...

...and it only tests up to the first failure

Page 55: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Tests in table

# Sequence Prefix Expected

Tests = [

['a', 'a', True],['a', 'a', True],

['at', 'a', True],

['at', 'at', True],

['at, 't', False]

]

Testing Introduction

Page 56: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Tests in table

# Sequence Prefix Expected

Tests = [

['a', 'a', True],

Easy to read

['a', 'a', True],

['at', 'a', True],

['at', 'at', True],

['at, 't', False]

]

Testing Introduction

Easy to read

Page 57: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Tests in table

# Sequence Prefix Expected

Tests = [

['a', 'a', True],

Easy to read

['a', 'a', True],

['at', 'a', True],

['at', 'at', True],

['at, 't', False]

]

Testing Introduction

Easy to read

Easy to add new tests

Page 58: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Run and report

passes = 0

forforforfor (seq, prefix, expected) inininin Tests:

ifififif dna_starts_with(seq, prefix) == expected:ifififif dna_starts_with(seq, prefix) == expected:

passes += 1

printprintprintprint '%d/%d tests passed' % (passes, len(Tests))

Testing Introduction

Page 59: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Run and report

passes = 0

forforforfor (seq, prefix, expected) inininin Tests:

ifififif dna_starts_with(seq, prefix) == expected:

No runnable code is copied when adding tests

ifififif dna_starts_with(seq, prefix) == expected:

passes += 1

printprintprintprint '%d/%d tests passed' % (passes, len(Tests))

Testing Introduction

Page 60: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Run and report

passes = 0

forforforfor (seq, prefix, expected) inininin Tests:

ifififif dna_starts_with(seq, prefix) == expected:

No runnable code is copied when adding tests

But when tests fail, we don't know which ones

ifififif dna_starts_with(seq, prefix) == expected:

passes += 1

printprintprintprint '%d/%d tests passed' % (passes, len(Tests))

Testing Introduction

But when tests fail, we don't know which ones

Page 61: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Run and report

passes = 0

forforforfor (i, (seq, prefix, expected)) inininin enumerate(Tests):

ifififif dna_starts_with(seq, prefix) == expected:ifififif dna_starts_with(seq, prefix) == expected:

passes += 1

elseelseelseelse:

printprintprintprint 'test %d failed' % i

printprintprintprint '%d/%d tests passed' % (passes, len(Tests))

Testing Introduction

Page 62: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Run and report

passes = 0

forforforfor (i, (seq, prefix, expected)) inininin enumerate(Tests):

ifififif dna_starts_with(seq, prefix) == expected:ifififif dna_starts_with(seq, prefix) == expected:

passes += 1

elseelseelseelse:

printprintprintprint 'test %d failed' % i

printprintprintprint '%d/%d tests passed' % (passes, len(Tests))

Testing Introduction

Produces (index, element)

for each element of list

Page 63: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Run and report

passes = 0

forforforfor (i, (seq, prefix, expected)) inininin enumerate(Tests):

ifififif dna_starts_with(seq, prefix) == expected:ifififif dna_starts_with(seq, prefix) == expected:

passes += 1

elseelseelseelse:

printprintprintprint 'test %d failed' % i

printprintprintprint '%d/%d tests passed' % (passes, len(Tests))

Testing Introduction

Decompose into variables

by matching structure

Page 64: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Run and report

passes = 0

forforforfor (i, (seq, prefix, expected)) inininin enumerate(Tests):

ifififif dna_starts_with(seq, prefix) == expected:ifififif dna_starts_with(seq, prefix) == expected:

passes += 1

elseelseelseelse:

printprintprintprint 'test %d failed' % i

printprintprintprint '%d/%d tests passed' % (passes, len(Tests))

Testing Introduction

Test passes as before

Page 65: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Run and report

passes = 0

forforforfor (i, (seq, prefix, expected)) inininin enumerate(Tests):

ifififif dna_starts_with(seq, prefix) == expected:ifififif dna_starts_with(seq, prefix) == expected:

passes += 1

elseelseelseelse:

printprintprintprint 'test %d failed' % i

printprintprintprint '%d/%d tests passed' % (passes, len(Tests))

Testing Introduction

Summarize results that

don't need attention

Page 66: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

# Run and report

passes = 0

forforforfor (i, (seq, prefix, expected)) inininin enumerate(Tests):

ifififif dna_starts_with(seq, prefix) == expected:ifififif dna_starts_with(seq, prefix) == expected:

passes += 1

elseelseelseelse:

printprintprintprint 'test %d failed' % i

printprintprintprint '%d/%d tests passed' % (passes, len(Tests))

Testing Introduction

Report each result that

needs attention separately

Page 67: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

This pattern is used for testing over and over

Testing Introduction

Page 68: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

This pattern is used for testing over and over

Many libraries to support it in many languages

Testing Introduction

Page 69: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

This pattern is used for testing over and over

Many libraries to support it in many languages

We'll look at one that comes with PythonWe'll look at one that comes with Python

Testing Introduction

Page 70: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

This pattern is used for testing over and over

Many libraries to support it in many languages

We'll look at one that comes with PythonWe'll look at one that comes with Python

But first, we'll look at how to handle errors

in programs systematically

Testing Introduction

Page 71: Testing - v4.software-carpentry.org · Nobody enjoys testing So you can skip this lecture if – your programs always work correctly, or – you don't care if they're correct or not,

July 2010

created by

Greg Wilson

July 2010

Copyright © Software Carpentry 2010

This work is licensed under the Creative Commons Attribution License

See http://software-carpentry.org/license.html for more information.