SlideShare uma empresa Scribd logo
1 de 101
Baixar para ler offline
What We Talk About
When We Talk About
Unit Testing
@KevlinHenney
kevlin@curbralan.com
Write down the problem.
Think real hard.
Write down the solution.
The Feynman Problem-Solving Algorithm
The update to SMARS was intended
to replace old, unused code
referred to as “Power Peg” —
functionality that Knight hadn’t
used in 8-years.
Doug Seven
http://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/
Why code that had been dead for 8
years was still present in the code
base is a mystery, but that’s not the
point.
Doug Seven
http://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/
In the first 45 minutes the market
was open the Power Peg code
received and processed 212 parent
orders. As a result SMARS sent
millions of child orders into the
market resulting in 4 million
transactions against 154 stocks for
more than 397 million shares.
Doug Seven
http://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/
Knight Capital Group realized a
$460 million loss in 45 minutes.
Doug Seven
http://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/
RUD, noun
 Rapid Unscheduled Disassembly
 Rocket science and amateur rocketry jargon that's acronymous,
euphemistic and explosively self-explanatory
WordFriday
The failure resulted in a loss
of more than US$370 million.
http://en.wikipedia.org/wiki/Cluster_(spacecraft)
Um. What's the name of the word for
things not being the same always. You
know, I'm sure there is one. Isn't there?
There's must be a word for it... the thing
that lets you know time is happening. Is
there a word?
Change.
Oh. I was afraid of that.
Neil Gaiman
The Sandman
What experience and
history teach is that
nations and governments
have never learned
anything from history.
Georg Wilhelm Friedrich Hegel
Write down the problem.
Think real hard.
Write down the solution.
Check it.
assert
void * bsearch(
const void * key,
const void * base,
size_t element_count,
size_t element_size,
int compare(const void * lhs, const void * rhs));
void * bsearch(
const void * key,
const void * base,
size_t element_count,
size_t element_size,
int compare(const void * lhs, const void * rhs))
{
...
void * result;
...
assert(???); // What is the postcondition?
return result;
}
void * bsearch(
const void * key,
const void * base,
size_t element_count,
size_t element_size,
int compare(const void * lhs, const void * rhs))
{
assert(???); // What is the precondition?
void * result;
...
assert(???); // What is the postcondition?
return result;
}
Test early.
Test often.
Test automatically.
Andrew Hunt and David Thomas
The Pragmatic Programmer
From time to time I hear people asking
what value of test coverage (also called
code coverage) they should aim for, or
stating their coverage levels with pride.
Such statements miss the point.
Martin Fowler
http://martinfowler.com/bliki/TestCoverage.html
I expect a high level of coverage.
Sometimes managers require one.
There's a subtle difference.
Brian Marick
http://martinfowler.com/bliki/TestCoverage.html
Goodhart's law, noun
 Once a metric becomes a target, it loses its meaning as
a measure.
 Named after Charles Goodhart, professor of economics
at the LSE and former advisor to the Bank of England,
who in 1975 observed that "Any observed statistical
regularity will tend to collapse once pressure is placed
upon it for control purposes."
https://www.facebook.com/WordFriday/posts/320731068014857
Developer Controls Process
Responsibilities of Developers
include understanding
requirements, reviewing the
solution structure and algorithm
with peers, building the
implementation, and unit testing.
A Generative Development-Process Pattern Language
James O Coplien
When you write unit tests, TDD-
style or after your development,
you scrutinize, you think, and
often you prevent problems
without even encountering a test
failure.
Michael Feathers
"The Flawed Theory Behind Unit Testing"
http://michaelfeathers.typepad.com/michael_feathers_blog/2008/06/the-flawed-theo.html
Very many people say "TDD"
when they really mean, "I have
good unit tests" ("I have GUTs"?).
Ron Jeffries tried for years to
explain what this was, but we
never got a catch-phrase for it,
and now TDD is being watered
down to mean GUTs.
Alistair Cockburn
"The modern programming professional has GUTs"
http://alistair.cockburn.us/The+modern+programming+professional+has+GUTs
size_t ints_to_csv(
const int * to_write, size_t how_many,
char * output, size_t length);
size_t ints_to_csv(
const int * to_write, size_t how_many, char * output, size_t length)
{
size_t result = 0;
if(length != 0)
{
if(how_many == 0)
{
output[0] = '0';
}
else
{
for(size_t which = 0; which != how_many && result != length; ++which)
{
result +=
snprintf(
output + result, length - result,
which == 0 ? "%i" : ",%i",
to_write[which]);
}
result = result > length - 1 ? length - 1 : result;
}
}
return result;
}
extern "C" size_t ints_to_csv(
const int * to_write, size_t how_many, char * output, size_t length)
{
size_t result = 0;
if(length != 0)
{
output[length - 1] = '0';
std::ostrstream buffer(output, length - 1);
for(size_t which = 0; which != how_many; ++which)
buffer << (which == 0 ? "" : ",") << to_write[which];
buffer << std::ends;
result = std::strlen(output);
}
return result;
}
functiontest
void test_ints_to_csv()
{
size_t written = ints_to_csv(NULL, 0, NULL, 0);
assert(written == 0);
const int input[] = { 42 };
written = ints_to_csv(input, 1, NULL, 0);
assert(written == 0);
char output[3] = "+++";
written = ints_to_csv(NULL, 0, output, sizeof output);
assert(written == 0);
assert(output[0] == '0');
memcpy(output, "+++", sizeof output);
written = ints_to_csv(input, 1, output, sizeof output);
assert(written == 2);
assert(strcmp(output, "42") == 0);
...
}
void test_ints_to_csv()
{
// No values from null to null output writes nothing
size_t written = ints_to_csv(NULL, 0, NULL, 0);
assert(written == 0);
// Value to null output writes nothing
const int input[] = { 42 };
written = ints_to_csv(input, 1, NULL, 0);
assert(written == 0);
// No values to sufficient output writes empty
char output[3] = "+++";
written = ints_to_csv(NULL, 0, output, sizeof output);
assert(written == 0);
assert(output[0] == '0');
// Positive value to sufficient output writes value without sign
memcpy(output, "+++", sizeof output);
written = ints_to_csv(input, 1, output, sizeof output);
assert(written == 2);
assert(strcmp(output, "42") == 0);
...
}
void test_ints_to_csv()
{
// No values from null to null output writes nothing
{
size_t written = ints_to_csv(NULL, 0, NULL, 0);
assert(written == 0);
}
// Value to null output writes nothing
{
const int input[] = { 42 };
size_t written = ints_to_csv(input, 1, NULL, 0);
assert(written == 0);
}
// No values to sufficient output writes empty
{
char output[3] = "+++";
size_t written = ints_to_csv(NULL, 0, output, sizeof output);
assert(written == 0);
assert(output[0] == '0');
}
// Positive value to sufficient output writes value without sign
{
const int input[] = { 42 };
char output[3] = "+++";
size_t written = ints_to_csv(input, 1, output, sizeof output);
assert(written == 2);
assert(strcmp(output, "42") == 0);
void No_values_from_null_to_null_output_writes_nothing()
{
size_t written = ints_to_csv(NULL, 0, NULL, 0);
assert(written == 0);
}
void Value_to_null_output_writes_nothing()
{
const int input[] = { 42 };
size_t written = ints_to_csv(input, 1, NULL, 0);
assert(written == 0);
}
void No_values_to_sufficient_output_writes_empty()
{
char output[3] = "+++";
size_t written = ints_to_csv(NULL, 0, output, sizeof output);
assert(written == 0);
assert(output[0] == '0');
}
void Positive_value_to_sufficient_output_writes_value_without_sign()
{
const int input[] = { 42 };
char output[3] = "+++";
size_t written = ints_to_csv(input, 1, output, sizeof output);
assert(written == 2);
assert(strcmp(output, "42") == 0);
}
void Negative_value_to_sufficient_output_writes_value_with_sign()
{
const int input[] = { -42 };
char output[4] = "++++";
size_t written = ints_to_csv(input, 1, output, sizeof output);
assert(written == 3);
assert(strcmp(output, "-42") == 0);
}
void Value_to_insufficient_output_writes_truncated_value()
{
const int input[] = { 42 };
char output[2] = "++";
size_t written = ints_to_csv(input, 1, output, sizeof output);
assert(written == 1);
assert(strcmp(output, "4") == 0);
}
void Multiple_values_to_sufficient_output_writes_comma_separated_values()
{
const int input[] = { 42, -273, 0, 7 };
char output[12] = "++++++++++++";
size_t written = ints_to_csv(input, 4, output, sizeof output);
assert(written == 11);
assert(strcmp(output, "42,-273,0,7") == 0);
}
void Multiple_values_to_insufficient_output_writes_truncated_value_sequence()
{
const int input[] = { 42, -273, 0, 7 };
char output[9] = "+++++++++";
size_t written = ints_to_csv(input, 4, output, sizeof output);
assert(written == 8);
assert(strcmp(output, "42,-273,") == 0);
}
void No_values_from_null_to_null_output_writes_nothing()
{
...
}
void Value_to_null_output_writes_nothing()
{
...
}
void No_values_to_sufficient_output_writes_empty()
{
...
}
void Positive_value_to_sufficient_output_writes_value_without_sign()
{
...
}
void Negative_value_to_sufficient_output_writes_value_with_sign()
{
...
}
void Value_to_insufficient_output_writes_truncated_value()
{
...
}
void Multiple_values_to_sufficient_output_writes_comma_separated_values()
{
...
}
void Multiple_values_to_insufficient_output_writes_truncated_value_sequence()
{
...
}
functiontest
test
test
size_t ints_to_csv(
const int * to_write, size_t how_many,
char * output, size_t length);
 No values from null to null output writes nothing
 Value to null output writes nothing
 No values to sufficient output writes empty
 Positive value to sufficient output writes value without sign
 Negative value to sufficient output writes value with sign
 Value to insufficient output writes truncated value
 Multiple values to sufficient output writes comma separated values
 Multiple values to insufficient output writes truncated value sequence
Tests that are not written with their
role as specifications in mind can
be very confusing to read. The
difficulty in understanding what
they are testing can greatly
reduce the velocity at which a
codebase can be changed.
Nat Pryce and Steve Freeman
"Are Your Tests Really Driving Your Development?"
Propositions
are vehicles
for stating
how things are
or might be.
Thus only indicative
sentences which it
makes sense to think
of as being true or as
being false are
capable of expressing
propositions.
public static bool IsLeapYear(int year) ...
YearsNotDivisibleBy4...
YearsDivisibleBy4ButNotBy100...
YearsDivisibleBy100ButNotBy400...
YearsDivisibleBy400...
Years_not_divisible_by_4_...
Years_divisible_by_4_but_not_by_100_...
Years_divisible_by_100_but_not_by_400_...
Years_divisible_by_400_...
Years_not_divisible_by_4_should_not_be_leap_years
Years_divisible_by_4_but_not_by_100_should_be_leap_years
Years_divisible_by_100_but_not_by_400_should_not_be_leap_years
Years_divisible_by_400_should_be_leap_years
Make definite assertions. Avoid tame,
colourless, hesitating, noncommittal
language.
Note [...] that when a sentence is made
stronger, it usually becomes shorter. Thus
brevity is a by-product of vigour.
William Strunk and E B White
The Elements of Style
Years_not_divisible_by_4_are_not_leap_years
Years_divisible_by_4_but_not_by_100_are_leap_years
Years_divisible_by_100_but_not_by_400_are_not_leap_years
Years_divisible_by_400_are_leap_years
Years_not_divisible_by_4_are_not_leap_years
Years_divisible_by_4_but_not_by_100_are_leap_years
Years_divisible_by_100_but_not_by_400_are_not_leap_years
Years_divisible_by_400_are_leap_years
Years_not_divisible_by_4_are_not_leap_years
Years_divisible_by_4_but_not_by_100_are_leap_years
Years_divisible_by_100_but_not_by_400_are_not_leap_years
Years_divisible_by_400_are_leap_years
A test case should
be just that: it
should correspond
to a single case.
namespace Leap_year_spec
{
[TestFixture]
public class A_year_is_a_leap_year
{
[Test] public void If_it_is_divisible_by_4_but_not_by_100() 
[Test] public void If_it_is_divisible_by_400() 
}
[TestFixture]
public class A_year_is_not_a_leap_year
{
[Test] public void If_it_is_not_divisible_by_4() 
[Test] public void If_it_is_divisible_by_100_but_not_by_400() 
}
}
namespace Leap_year_spec
{
[TestFixture]
public class A_year_is_a_leap_year
{
[Test] public void If_it_is_divisible_by_4_but_not_by_100() 
[Test] public void If_it_is_divisible_by_400() 
}
[TestFixture]
public class A_year_is_not_a_leap_year
{
[Test] public void If_it_is_not_divisible_by_4() 
[Test] public void If_it_is_divisible_by_100_but_not_by_400() 
}
}
namespace Leap_year_spec
{
[TestFixture]
public class A_year_is_a_leap_year
{
[Test] public void If_it_is_divisible_by_4_but_not_by_100() 
[Test] public void If_it_is_divisible_by_400() 
}
[TestFixture]
public class A_year_is_not_a_leap_year
{
[Test] public void If_it_is_not_divisible_by_4() 
[Test] public void If_it_is_divisible_by_100_but_not_by_400() 
}
}
namespace Leap_year_spec
{
[TestFixture]
public class A_year_is_a_leap_year
{
[Test]
public void If_it_is_divisible_by_4_but_not_by_100(
[Values(2012, 1984, 4)] int year)
{
Assert.IsTrue(IsLeapYear(year));
}
[Test]
public void If_it_is_divisible_by_400(
[Range(400, 2400, 400)] int year)
{
Assert.IsTrue(IsLeapYear(year));
}
}
[TestFixture]
public class A_year_is_not_a_leap_year
{
[Test] public void If_it_is_not_divisible_by_4() 
[Test] public void If_it_is_divisible_by_100_but_not_by_400() 
}
}
namespace Leap_year_spec
{
[TestFixture]
public class A_year_is_a_leap_year
{
[Test]
public void If_it_is_divisible_by_4_but_not_by_100(
[Values(2012, 1984, 4)] int year)
{
Assert.IsTrue(IsLeapYear(year));
}
[Test]
public void If_it_is_divisible_by_400(
[Range(400, 2400, 400)] int year)
{
Assert.IsTrue(IsLeapYear(year));
}
}
[TestFixture]
public class A_year_is_not_a_leap_year
{
[Test] public void If_it_is_not_divisible_by_4() 
[Test] public void If_it_is_divisible_by_100_but_not_by_400() 
}
}
namespace Leap_year_spec
{
[TestFixture]
public class A_year_is_either_a_leap_year_or_not
{
[Test]
public void IsLeapYear_is_correct([Range(1, 10000)] int year) 
}
}
namespace Leap_year_spec
{
[TestFixture]
public class A_year_is_either_a_leap_year_or_not
{
[Test]
public void IsLeapYear_is_correct([Range(1, 10000)] int year)
{
Assert.AreEqual(
year % 4 == 0 && year % 100 != 0 || year % 400 == 0,
IsLeapYear(year));
}
}
}
namespace Leap_year_spec
{
[TestFixture]
public class A_year_is_either_a_leap_year_or_not
{
[Test]
public void IsLeapYear_is_correct([Range(1, 10000)] int year)
{
Assert.AreEqual(LeapYearExpectation(year), IsLeapYear(year));
}
public static bool LeapYearExpectation(int year)
{
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}
}
}
public static bool IsLeapYear(int year)
{
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}
All happy families are alike;
each unhappy family is
unhappy in its own way.
Leo Tolstoy
Anna Karenina
proposition isbn_spec[] =
{
...
"Test validation", []
{
CATCH(isbn("97805968094857"), isbn::malformed);
CATCH(isbn("978059680948"), isbn::malformed);
CATCH(isbn("978Q5968=9485"), isbn::malformed);
CATCH(isbn("9780596809486"), isbn::malformed);
},
...
};
struct proposition
{
std::string name;
std::function<void()> run;
};
struct failure
{
const char * expression;
int line;
};
template<typename Propositions>
void test(const Propositions & to_test)
{
for(auto & test : to_test)
{
try
{
std::cout << test.name << std::flush;
test.run();
std::cout << "n";
}
catch(failure & caught)
{
std::cout << " failed:n " << caught.expression << "n at line " << caught.line << "n";
}
}
}
#define ASSERT(condition) void((condition) ? 0 : throw failure({ "ASSERT(" #condition ")", __LINE__ }))
#define CATCH(expression, exception) 
try 
{ 
(expression); 
throw failure({ "CATCH(" #expression ", " #exception ")", __LINE__ }); 
} 
catch (exception &) 
{ 
} 
catch (...) 
{ 
throw failure({ "CATCH(" #expression ", " #exception ")", __LINE__ }); 
}
proposition isbn_spec[] =
{
...
"Test validation", []
{
CATCH(isbn("97805968094857"), isbn::malformed);
CATCH(isbn("978059680948"), isbn::malformed);
CATCH(isbn("978Q5968=9485"), isbn::malformed);
CATCH(isbn("9780596809486"), isbn::malformed);
},
...
};
proposition isbn_spec[] =
{
...
"Test validation", []
{
CATCH(isbn("97805968094857"), isbn::malformed);
CATCH(isbn("978059680948"), isbn::malformed);
CATCH(isbn("978Q5968=9485"), isbn::malformed);
CATCH(isbn("9780596809486"), isbn::malformed);
},
...
};
proposition isbn_spec[] =
{
...
"Test validation works", []
{
CATCH(isbn("97805968094857"), isbn::malformed);
CATCH(isbn("978059680948"), isbn::malformed);
CATCH(isbn("978Q5968=9485"), isbn::malformed);
CATCH(isbn("9780596809486"), isbn::malformed);
},
...
};
proposition isbn_spec[] =
{
...
"Test validation works", []
{
CATCH(isbn("97805968094857"), isbn::malformed);
CATCH(isbn("978059680948"), isbn::malformed);
CATCH(isbn("978Q5968=9485"), isbn::malformed);
CATCH(isbn("9780596809486"), isbn::malformed);
},
...
};
proposition isbn_spec[] =
{
...
"ISBNs with more than 13 digits are malformed", []
{
CATCH(isbn("97805968094857"), isbn::malformed);
},
"ISBNs with fewer than 13 digits are malformed", []
{
CATCH(isbn("978059680948"), isbn::malformed);
},
"ISBNs with non-digits are malformed", []
{
CATCH(isbn("978Q5968=9485"), isbn::malformed);
},
"ISBNs with an incorrect check digit are malformed", []
{
CATCH(isbn("9780596809486"), isbn::malformed);
},
...
};
proposition isbn_spec[] =
{
...
"ISBNs with more than 13 digits are malformed", []
{
CATCH(isbn("97805968094857"), isbn::malformed);
},
"ISBNs with fewer than 13 digits are malformed", []
{
CATCH(isbn("978059680948"), isbn::malformed);
},
"ISBNs with non-digits are malformed", []
{
CATCH(isbn("978Q5968=9485"), isbn::malformed);
},
"ISBNs with an incorrect check digit are malformed", []
{
CATCH(isbn("9780596809486"), isbn::malformed);
},
...
};
Validation is not
a behaviour; the
consequence of
validation is.
methodtest
test
test
method
method
public class RecentlyUsedList
{
...
public RecentlyUsedList() ...
public int Count
{
get...
}
public string this[int index]
{
get...
}
public void Add(string newItem) ...
...
}
[TestFixture]
public class RecentlyUsedListTests
{
[Test]
public void TestConstructor() ...
[Test]
public void TestCountGet() ...
[Test]
public void TestIndexerGet() ...
[Test]
public void TestAdd() ...
...
}
methodtest
test
test
method
method
test
test
namespace RecentlyUsedList_spec
{
[TestFixture]
public class A_new_list
{
[Test] public void Is_empty() 
}
[TestFixture]
public class An_empty_list
{
[Test] public void Retains_a_single_addition() 
[Test] public void Retains_unique_additions_in_stack_order() 
}
[TestFixture]
public class A_non_empty_list
{
[Test] public void Is_unchanged_when_head_item_is_readded() 
[Test] public void Moves_non_head_item_to_head_when_it_is_readded() 
}
[TestFixture]
public class Any_list_rejects
{
[Test] public void Addition_of_null_items() 
[Test] public void Indexing_past_its_end() 
[Test] public void Negative_indexing() 
}
}
namespace RecentlyUsedList_spec
{
[TestFixture]
public class A_new_list
{
[Test] public void Is_empty() 
}
[TestFixture]
public class An_empty_list
{
[Test] public void Retains_a_single_addition() 
[Test] public void Retains_unique_additions_in_stack_order() 
}
[TestFixture]
public class A_non_empty_list
{
[Test] public void Is_unchanged_when_head_item_is_readded() 
[Test] public void Moves_non_head_item_to_head_when_it_is_readded() 
}
[TestFixture]
public class Any_list_rejects
{
[Test] public void Addition_of_null_items() 
[Test] public void Indexing_past_its_end() 
[Test] public void Negative_indexing() 
}
}
So who should you be writing the tests
for? For the person trying to
understand your code.
Good tests act as documentation for
the code they are testing. They
describe how the code works. For each
usage scenario, the test(s):
 Describe the context, starting point,
or preconditions that must be
satisfied
 Illustrate how the software is
invoked
 Describe the expected results or
postconditions to be verified
Different usage scenarios will have
slightly different versions of each of
these.
Gerard Meszaros
"Write Tests for People"
namespace RecentlyUsedList_spec
{
[TestFixture]
public class A_new_list ...
[TestFixture]
public class An_empty_list
{
[Test]
public void Retains_a_single_addition(
[Values("Oxford", "Bristol", "London")] string addend)
{
var items = new RecentlyUsedList(); // Given...
items.Add(addend); // When...
Assert.AreEqual(1, items.Count); // Then...
Assert.AreEqual(addend, list[0]);
}
[Test] public void Retains_unique_additions_in_stack_order() 
}
[TestFixture]
public class A_non_empty_list ...
[TestFixture]
public class Any_list_rejects ...
}
One of the things that Osherove warns
against is multiple asserts in unit tests.
Owen Pellegrin
http://www.owenpellegrin.com/blog/testing/how-do-you-solve-multiple-asserts/
Proper unit tests should fail for exactly
one reason, that’s why you should be
using one assert per unit test.
http://rauchy.net/oapt/
string[] itinerary = ...;
string[] expected =
{
"London", "Bristol", "Oslo"
};
Assert.AreEqual(expected, itinerary);
Assert.IsNotNull(itinerary);
Assert.AreEqual(3, itinerary.Length);
Assert.AreEqual("London", itinerary[0]);
Assert.AreEqual("Bristol", itinerary[1]);
Assert.AreEqual("Oslo", itinerary[2]);
Assert.DoesNotThrow(() =>
{
string[] itinerary = ...;
string[] expected = ...;
});
new Expectations()
{{
...
}}
@Test(expected=...)
public void ...()
{
...
}
def ...()
{
...
expect:
...
}
My guideline is usually that you test
one logical concept per test. You can
have multiple asserts on the same
object. They will usually be the same
concept being tested.
Roy Osherove
http://www.owenpellegrin.com/blog/testing/how-do-you-solve-multiple-asserts/
One of the most foundational
principles of good design is:
Gather together those things
that change for the same
reason, and separate those
things that change for
different reasons.
This principle is often known
as the single responsibility
principle, or SRP. In short, it
says that a subsystem, module,
class, or even a function,
should not have more than one
reason to change.
classtests
tests class
tests
tests
A test is not a unit test if:
 It talks to the database
 It communicates across the network
 It touches the file system
 It can't run at the same time as any of your other unit tests
 You have to do special things to your environment (such as
editing config files) to run it.
Tests that do these things aren't bad. Often they are worth
writing, and they can be written in a unit test harness.
However, it is important to be able to separate them from true
unit tests so that we can keep a set of tests that we can run fast
whenever we make our changes.
Michael Feathers
"A Set of Unit Testing Rules"
http://www.artima.com/weblogs/viewpost.jsp?thread=126923
A unit test is a test of
behaviour whose success
or failure is wholly
determined by the
correctness of the test
and the correctness of
the unit under test.
Kevlin Henney
http://www.theregister.co.uk/2007/07/28/what_are_your_units/
Necessarily not unit
testable, such as
interactions with
external dependencies
Unit testable in practice
Unit testable in theory,
but not unit testable in
practice
Mutable
Immutable
Unshared Shared
Unshared mutable
data needs no
synchronisation
Unshared immutable
data needs no
synchronisation
Shared mutable
data needs
synchronisation
Shared immutable
data needs no
synchronisation
Mutable
Immutable
Unshared Shared
Unshared mutable
data needs no
synchronisation
Unshared immutable
data needs no
synchronisation
Shared mutable
data needs
synchronisation
Shared immutable
data needs no
synchronisation
The Synchronisation Quadrant
The real value of tests is
not that they detect bugs
in the code but that they
detect inadequacies in the
methods, concentration, and
skills of those who design
and produce the code.
C A R Hoare

Mais conteúdo relacionado

Mais procurados

C tech questions
C tech questionsC tech questions
C tech questionsvijay00791
 
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...ssuserd6b1fd
 
How to not write a boring test in Golang
How to not write a boring test in GolangHow to not write a boring test in Golang
How to not write a boring test in GolangDan Tran
 
C++ L02-Conversion+enum+Operators
C++ L02-Conversion+enum+OperatorsC++ L02-Conversion+enum+Operators
C++ L02-Conversion+enum+OperatorsMohammad Shaker
 
C++ Programming - 11th Study
C++ Programming - 11th StudyC++ Programming - 11th Study
C++ Programming - 11th StudyChris Ohk
 
C++ L03-Control Structure
C++ L03-Control StructureC++ L03-Control Structure
C++ L03-Control StructureMohammad Shaker
 
Notes for C++ Programming / Object Oriented C++ Programming for MCA, BCA and ...
Notes for C++ Programming / Object Oriented C++ Programming for MCA, BCA and ...Notes for C++ Programming / Object Oriented C++ Programming for MCA, BCA and ...
Notes for C++ Programming / Object Oriented C++ Programming for MCA, BCA and ...ssuserd6b1fd
 
An imperative study of c
An imperative study of cAn imperative study of c
An imperative study of cTushar B Kute
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with PythonHan Lee
 

Mais procurados (20)

C++ L06-Pointers
C++ L06-PointersC++ L06-Pointers
C++ L06-Pointers
 
C tech questions
C tech questionsC tech questions
C tech questions
 
Cquestions
Cquestions Cquestions
Cquestions
 
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
Notes for C Programming for MCA, BCA, B. Tech CSE, ECE and MSC (CS) 4 of 5 by...
 
C++ L07-Struct
C++ L07-StructC++ L07-Struct
C++ L07-Struct
 
C program
C programC program
C program
 
C++ L04-Array+String
C++ L04-Array+StringC++ L04-Array+String
C++ L04-Array+String
 
C++ L01-Variables
C++ L01-VariablesC++ L01-Variables
C++ L01-Variables
 
How to not write a boring test in Golang
How to not write a boring test in GolangHow to not write a boring test in Golang
How to not write a boring test in Golang
 
Stl algorithm-Basic types
Stl algorithm-Basic typesStl algorithm-Basic types
Stl algorithm-Basic types
 
C++ L02-Conversion+enum+Operators
C++ L02-Conversion+enum+OperatorsC++ L02-Conversion+enum+Operators
C++ L02-Conversion+enum+Operators
 
Arrays
ArraysArrays
Arrays
 
C++ Programming - 11th Study
C++ Programming - 11th StudyC++ Programming - 11th Study
C++ Programming - 11th Study
 
C++ L05-Functions
C++ L05-FunctionsC++ L05-Functions
C++ L05-Functions
 
C++ L03-Control Structure
C++ L03-Control StructureC++ L03-Control Structure
C++ L03-Control Structure
 
Notes for C++ Programming / Object Oriented C++ Programming for MCA, BCA and ...
Notes for C++ Programming / Object Oriented C++ Programming for MCA, BCA and ...Notes for C++ Programming / Object Oriented C++ Programming for MCA, BCA and ...
Notes for C++ Programming / Object Oriented C++ Programming for MCA, BCA and ...
 
An imperative study of c
An imperative study of cAn imperative study of c
An imperative study of c
 
Array notes
Array notesArray notes
Array notes
 
C++ L11-Polymorphism
C++ L11-PolymorphismC++ L11-Polymorphism
C++ L11-Polymorphism
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
 

Destaque

Become a Great Communicator
Become a Great CommunicatorBecome a Great Communicator
Become a Great CommunicatorTony Santiago
 
Spoken english classes in kalewadi phata
Spoken english classes in kalewadi phataSpoken english classes in kalewadi phata
Spoken english classes in kalewadi phataRaj Kumar
 
Unidad 1 MOOC MVC
Unidad 1 MOOC MVCUnidad 1 MOOC MVC
Unidad 1 MOOC MVCscolomina
 
Speak better English here's how.
Speak better English here's how.Speak better English here's how.
Speak better English here's how.James Russell
 
1st qtr 16 use variety of sentences
1st qtr 16 use variety of sentences1st qtr 16 use variety of sentences
1st qtr 16 use variety of sentencesShirley Sison
 
Writing code you won't hate tomorrow
Writing code you won't hate tomorrowWriting code you won't hate tomorrow
Writing code you won't hate tomorrowRafael Dohms
 
Programming with Threads in Java
Programming with Threads in JavaProgramming with Threads in Java
Programming with Threads in Javakoji lin
 
Learn english | Talk English
Learn english | Talk EnglishLearn english | Talk English
Learn english | Talk EnglishGowri S
 
Learning spoken Language.
Learning spoken Language.Learning spoken Language.
Learning spoken Language.RoberAgainst
 
Speaking tips
Speaking tipsSpeaking tips
Speaking tipstweetya
 
Java Spring MVC Framework with AngularJS by Google and HTML5
Java Spring MVC Framework with AngularJS by Google and HTML5Java Spring MVC Framework with AngularJS by Google and HTML5
Java Spring MVC Framework with AngularJS by Google and HTML5Tuna Tore
 

Destaque (20)

Spring mvc
Spring mvcSpring mvc
Spring mvc
 
Become a Great Communicator
Become a Great CommunicatorBecome a Great Communicator
Become a Great Communicator
 
Spoken english classes in kalewadi phata
Spoken english classes in kalewadi phataSpoken english classes in kalewadi phata
Spoken english classes in kalewadi phata
 
Unidad 1 MOOC MVC
Unidad 1 MOOC MVCUnidad 1 MOOC MVC
Unidad 1 MOOC MVC
 
Speak better English here's how.
Speak better English here's how.Speak better English here's how.
Speak better English here's how.
 
1st qtr 16 use variety of sentences
1st qtr 16 use variety of sentences1st qtr 16 use variety of sentences
1st qtr 16 use variety of sentences
 
Spring mvc
Spring mvcSpring mvc
Spring mvc
 
Writing code you won't hate tomorrow
Writing code you won't hate tomorrowWriting code you won't hate tomorrow
Writing code you won't hate tomorrow
 
Threads in Java
Threads in JavaThreads in Java
Threads in Java
 
Programming with Threads in Java
Programming with Threads in JavaProgramming with Threads in Java
Programming with Threads in Java
 
Learn english | Talk English
Learn english | Talk EnglishLearn english | Talk English
Learn english | Talk English
 
Basic java tutorial
Basic java tutorialBasic java tutorial
Basic java tutorial
 
Mis ethical social
Mis ethical socialMis ethical social
Mis ethical social
 
Threads in java
Threads in javaThreads in java
Threads in java
 
Memory Module Network - MMN
Memory Module Network - MMNMemory Module Network - MMN
Memory Module Network - MMN
 
Learning spoken Language.
Learning spoken Language.Learning spoken Language.
Learning spoken Language.
 
The truth of spoken english business
The truth of spoken english businessThe truth of spoken english business
The truth of spoken english business
 
Speaking tips
Speaking tipsSpeaking tips
Speaking tips
 
Spring MVC Basics
Spring MVC BasicsSpring MVC Basics
Spring MVC Basics
 
Java Spring MVC Framework with AngularJS by Google and HTML5
Java Spring MVC Framework with AngularJS by Google and HTML5Java Spring MVC Framework with AngularJS by Google and HTML5
Java Spring MVC Framework with AngularJS by Google and HTML5
 

Semelhante a What We Talk About When We Talk About Unit Testing

Programming with GUTs
Programming with GUTsProgramming with GUTs
Programming with GUTsKevlin Henney
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4Abed Bukhari
 
Some examples of the 64-bit code errors
Some examples of the 64-bit code errorsSome examples of the 64-bit code errors
Some examples of the 64-bit code errorsPVS-Studio
 
Is writing performant code too expensive?
Is writing performant code too expensive? Is writing performant code too expensive?
Is writing performant code too expensive? Tomasz Kowalczewski
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Juan Pablo
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerAndrey Karpov
 
Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...Arthur Puthin
 
LECTURE 3 LOOPS, ARRAYS.pdf
LECTURE 3 LOOPS, ARRAYS.pdfLECTURE 3 LOOPS, ARRAYS.pdf
LECTURE 3 LOOPS, ARRAYS.pdfSHASHIKANT346021
 
An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test frameworkAbner Chih Yi Huang
 
YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE .docx
 YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE .docx YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE .docx
YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE .docxgertrudebellgrove
 

Semelhante a What We Talk About When We Talk About Unit Testing (20)

Programming with GUTs
Programming with GUTsProgramming with GUTs
Programming with GUTs
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4
 
Java Basics - Part1
Java Basics - Part1Java Basics - Part1
Java Basics - Part1
 
Some examples of the 64-bit code errors
Some examples of the 64-bit code errorsSome examples of the 64-bit code errors
Some examples of the 64-bit code errors
 
Is writing performant code too expensive?
Is writing performant code too expensive? Is writing performant code too expensive?
Is writing performant code too expensive?
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
C tutorial
C tutorialC tutorial
C tutorial
 
C tutorial
C tutorialC tutorial
C tutorial
 
C tutorial
C tutorialC tutorial
C tutorial
 
C tutorial
C tutorialC tutorial
C tutorial
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical Reviewer
 
C tutorial
C tutorialC tutorial
C tutorial
 
Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...
 
A Test of Strength
A Test of StrengthA Test of Strength
A Test of Strength
 
Kpi driven-java-development-fn conf
Kpi driven-java-development-fn confKpi driven-java-development-fn conf
Kpi driven-java-development-fn conf
 
Writing Good Tests
Writing Good TestsWriting Good Tests
Writing Good Tests
 
Price of an Error
Price of an ErrorPrice of an Error
Price of an Error
 
LECTURE 3 LOOPS, ARRAYS.pdf
LECTURE 3 LOOPS, ARRAYS.pdfLECTURE 3 LOOPS, ARRAYS.pdf
LECTURE 3 LOOPS, ARRAYS.pdf
 
An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test framework
 
YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE .docx
 YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE .docx YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE .docx
YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE .docx
 

Mais de Kevlin Henney

The Case for Technical Excellence
The Case for Technical ExcellenceThe Case for Technical Excellence
The Case for Technical ExcellenceKevlin Henney
 
Empirical Development
Empirical DevelopmentEmpirical Development
Empirical DevelopmentKevlin Henney
 
Lambda? You Keep Using that Letter
Lambda? You Keep Using that LetterLambda? You Keep Using that Letter
Lambda? You Keep Using that LetterKevlin Henney
 
Lambda? You Keep Using that Letter
Lambda? You Keep Using that LetterLambda? You Keep Using that Letter
Lambda? You Keep Using that LetterKevlin Henney
 
Solid Deconstruction
Solid DeconstructionSolid Deconstruction
Solid DeconstructionKevlin Henney
 
Procedural Programming: It’s Back? It Never Went Away
Procedural Programming: It’s Back? It Never Went AwayProcedural Programming: It’s Back? It Never Went Away
Procedural Programming: It’s Back? It Never Went AwayKevlin Henney
 
Structure and Interpretation of Test Cases
Structure and Interpretation of Test CasesStructure and Interpretation of Test Cases
Structure and Interpretation of Test CasesKevlin Henney
 
Refactoring to Immutability
Refactoring to ImmutabilityRefactoring to Immutability
Refactoring to ImmutabilityKevlin Henney
 
Turning Development Outside-In
Turning Development Outside-InTurning Development Outside-In
Turning Development Outside-InKevlin Henney
 
Giving Code a Good Name
Giving Code a Good NameGiving Code a Good Name
Giving Code a Good NameKevlin Henney
 
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...Kevlin Henney
 
Thinking Outside the Synchronisation Quadrant
Thinking Outside the Synchronisation QuadrantThinking Outside the Synchronisation Quadrant
Thinking Outside the Synchronisation QuadrantKevlin Henney
 

Mais de Kevlin Henney (20)

Program with GUTs
Program with GUTsProgram with GUTs
Program with GUTs
 
The Case for Technical Excellence
The Case for Technical ExcellenceThe Case for Technical Excellence
The Case for Technical Excellence
 
Empirical Development
Empirical DevelopmentEmpirical Development
Empirical Development
 
Lambda? You Keep Using that Letter
Lambda? You Keep Using that LetterLambda? You Keep Using that Letter
Lambda? You Keep Using that Letter
 
Lambda? You Keep Using that Letter
Lambda? You Keep Using that LetterLambda? You Keep Using that Letter
Lambda? You Keep Using that Letter
 
Solid Deconstruction
Solid DeconstructionSolid Deconstruction
Solid Deconstruction
 
Get Kata
Get KataGet Kata
Get Kata
 
Procedural Programming: It’s Back? It Never Went Away
Procedural Programming: It’s Back? It Never Went AwayProcedural Programming: It’s Back? It Never Went Away
Procedural Programming: It’s Back? It Never Went Away
 
Structure and Interpretation of Test Cases
Structure and Interpretation of Test CasesStructure and Interpretation of Test Cases
Structure and Interpretation of Test Cases
 
Agility ≠ Speed
Agility ≠ SpeedAgility ≠ Speed
Agility ≠ Speed
 
Refactoring to Immutability
Refactoring to ImmutabilityRefactoring to Immutability
Refactoring to Immutability
 
Old Is the New New
Old Is the New NewOld Is the New New
Old Is the New New
 
Turning Development Outside-In
Turning Development Outside-InTurning Development Outside-In
Turning Development Outside-In
 
Giving Code a Good Name
Giving Code a Good NameGiving Code a Good Name
Giving Code a Good Name
 
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
 
Thinking Outside the Synchronisation Quadrant
Thinking Outside the Synchronisation QuadrantThinking Outside the Synchronisation Quadrant
Thinking Outside the Synchronisation Quadrant
 
Code as Risk
Code as RiskCode as Risk
Code as Risk
 
Software Is Details
Software Is DetailsSoftware Is Details
Software Is Details
 
Game of Sprints
Game of SprintsGame of Sprints
Game of Sprints
 
Good Code
Good CodeGood Code
Good Code
 

Último

Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 

Último (20)

Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 

What We Talk About When We Talk About Unit Testing

  • 1. What We Talk About When We Talk About Unit Testing @KevlinHenney kevlin@curbralan.com
  • 2. Write down the problem. Think real hard. Write down the solution. The Feynman Problem-Solving Algorithm
  • 3.
  • 4.
  • 5.
  • 6. The update to SMARS was intended to replace old, unused code referred to as “Power Peg” — functionality that Knight hadn’t used in 8-years. Doug Seven http://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/
  • 7. Why code that had been dead for 8 years was still present in the code base is a mystery, but that’s not the point. Doug Seven http://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/
  • 8. In the first 45 minutes the market was open the Power Peg code received and processed 212 parent orders. As a result SMARS sent millions of child orders into the market resulting in 4 million transactions against 154 stocks for more than 397 million shares. Doug Seven http://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/
  • 9. Knight Capital Group realized a $460 million loss in 45 minutes. Doug Seven http://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/
  • 10. RUD, noun  Rapid Unscheduled Disassembly  Rocket science and amateur rocketry jargon that's acronymous, euphemistic and explosively self-explanatory WordFriday
  • 11.
  • 12. The failure resulted in a loss of more than US$370 million. http://en.wikipedia.org/wiki/Cluster_(spacecraft)
  • 13.
  • 14. Um. What's the name of the word for things not being the same always. You know, I'm sure there is one. Isn't there? There's must be a word for it... the thing that lets you know time is happening. Is there a word? Change. Oh. I was afraid of that. Neil Gaiman The Sandman
  • 15. What experience and history teach is that nations and governments have never learned anything from history. Georg Wilhelm Friedrich Hegel
  • 16. Write down the problem. Think real hard. Write down the solution. Check it.
  • 18. void * bsearch( const void * key, const void * base, size_t element_count, size_t element_size, int compare(const void * lhs, const void * rhs));
  • 19. void * bsearch( const void * key, const void * base, size_t element_count, size_t element_size, int compare(const void * lhs, const void * rhs)) { ... void * result; ... assert(???); // What is the postcondition? return result; }
  • 20. void * bsearch( const void * key, const void * base, size_t element_count, size_t element_size, int compare(const void * lhs, const void * rhs)) { assert(???); // What is the precondition? void * result; ... assert(???); // What is the postcondition? return result; }
  • 21.
  • 22. Test early. Test often. Test automatically. Andrew Hunt and David Thomas The Pragmatic Programmer
  • 23. From time to time I hear people asking what value of test coverage (also called code coverage) they should aim for, or stating their coverage levels with pride. Such statements miss the point. Martin Fowler http://martinfowler.com/bliki/TestCoverage.html
  • 24. I expect a high level of coverage. Sometimes managers require one. There's a subtle difference. Brian Marick http://martinfowler.com/bliki/TestCoverage.html
  • 25. Goodhart's law, noun  Once a metric becomes a target, it loses its meaning as a measure.  Named after Charles Goodhart, professor of economics at the LSE and former advisor to the Bank of England, who in 1975 observed that "Any observed statistical regularity will tend to collapse once pressure is placed upon it for control purposes." https://www.facebook.com/WordFriday/posts/320731068014857
  • 26.
  • 27. Developer Controls Process Responsibilities of Developers include understanding requirements, reviewing the solution structure and algorithm with peers, building the implementation, and unit testing. A Generative Development-Process Pattern Language James O Coplien
  • 28. When you write unit tests, TDD- style or after your development, you scrutinize, you think, and often you prevent problems without even encountering a test failure. Michael Feathers "The Flawed Theory Behind Unit Testing" http://michaelfeathers.typepad.com/michael_feathers_blog/2008/06/the-flawed-theo.html
  • 29. Very many people say "TDD" when they really mean, "I have good unit tests" ("I have GUTs"?). Ron Jeffries tried for years to explain what this was, but we never got a catch-phrase for it, and now TDD is being watered down to mean GUTs. Alistair Cockburn "The modern programming professional has GUTs" http://alistair.cockburn.us/The+modern+programming+professional+has+GUTs
  • 30. size_t ints_to_csv( const int * to_write, size_t how_many, char * output, size_t length);
  • 31. size_t ints_to_csv( const int * to_write, size_t how_many, char * output, size_t length) { size_t result = 0; if(length != 0) { if(how_many == 0) { output[0] = '0'; } else { for(size_t which = 0; which != how_many && result != length; ++which) { result += snprintf( output + result, length - result, which == 0 ? "%i" : ",%i", to_write[which]); } result = result > length - 1 ? length - 1 : result; } } return result; }
  • 32. extern "C" size_t ints_to_csv( const int * to_write, size_t how_many, char * output, size_t length) { size_t result = 0; if(length != 0) { output[length - 1] = '0'; std::ostrstream buffer(output, length - 1); for(size_t which = 0; which != how_many; ++which) buffer << (which == 0 ? "" : ",") << to_write[which]; buffer << std::ends; result = std::strlen(output); } return result; }
  • 34. void test_ints_to_csv() { size_t written = ints_to_csv(NULL, 0, NULL, 0); assert(written == 0); const int input[] = { 42 }; written = ints_to_csv(input, 1, NULL, 0); assert(written == 0); char output[3] = "+++"; written = ints_to_csv(NULL, 0, output, sizeof output); assert(written == 0); assert(output[0] == '0'); memcpy(output, "+++", sizeof output); written = ints_to_csv(input, 1, output, sizeof output); assert(written == 2); assert(strcmp(output, "42") == 0); ... }
  • 35. void test_ints_to_csv() { // No values from null to null output writes nothing size_t written = ints_to_csv(NULL, 0, NULL, 0); assert(written == 0); // Value to null output writes nothing const int input[] = { 42 }; written = ints_to_csv(input, 1, NULL, 0); assert(written == 0); // No values to sufficient output writes empty char output[3] = "+++"; written = ints_to_csv(NULL, 0, output, sizeof output); assert(written == 0); assert(output[0] == '0'); // Positive value to sufficient output writes value without sign memcpy(output, "+++", sizeof output); written = ints_to_csv(input, 1, output, sizeof output); assert(written == 2); assert(strcmp(output, "42") == 0); ... }
  • 36. void test_ints_to_csv() { // No values from null to null output writes nothing { size_t written = ints_to_csv(NULL, 0, NULL, 0); assert(written == 0); } // Value to null output writes nothing { const int input[] = { 42 }; size_t written = ints_to_csv(input, 1, NULL, 0); assert(written == 0); } // No values to sufficient output writes empty { char output[3] = "+++"; size_t written = ints_to_csv(NULL, 0, output, sizeof output); assert(written == 0); assert(output[0] == '0'); } // Positive value to sufficient output writes value without sign { const int input[] = { 42 }; char output[3] = "+++"; size_t written = ints_to_csv(input, 1, output, sizeof output); assert(written == 2); assert(strcmp(output, "42") == 0);
  • 37. void No_values_from_null_to_null_output_writes_nothing() { size_t written = ints_to_csv(NULL, 0, NULL, 0); assert(written == 0); } void Value_to_null_output_writes_nothing() { const int input[] = { 42 }; size_t written = ints_to_csv(input, 1, NULL, 0); assert(written == 0); } void No_values_to_sufficient_output_writes_empty() { char output[3] = "+++"; size_t written = ints_to_csv(NULL, 0, output, sizeof output); assert(written == 0); assert(output[0] == '0'); } void Positive_value_to_sufficient_output_writes_value_without_sign() { const int input[] = { 42 }; char output[3] = "+++"; size_t written = ints_to_csv(input, 1, output, sizeof output); assert(written == 2); assert(strcmp(output, "42") == 0); } void Negative_value_to_sufficient_output_writes_value_with_sign() { const int input[] = { -42 }; char output[4] = "++++"; size_t written = ints_to_csv(input, 1, output, sizeof output); assert(written == 3); assert(strcmp(output, "-42") == 0); } void Value_to_insufficient_output_writes_truncated_value() { const int input[] = { 42 }; char output[2] = "++"; size_t written = ints_to_csv(input, 1, output, sizeof output); assert(written == 1); assert(strcmp(output, "4") == 0); } void Multiple_values_to_sufficient_output_writes_comma_separated_values() { const int input[] = { 42, -273, 0, 7 }; char output[12] = "++++++++++++"; size_t written = ints_to_csv(input, 4, output, sizeof output); assert(written == 11); assert(strcmp(output, "42,-273,0,7") == 0); } void Multiple_values_to_insufficient_output_writes_truncated_value_sequence() { const int input[] = { 42, -273, 0, 7 }; char output[9] = "+++++++++"; size_t written = ints_to_csv(input, 4, output, sizeof output); assert(written == 8); assert(strcmp(output, "42,-273,") == 0); }
  • 38. void No_values_from_null_to_null_output_writes_nothing() { ... } void Value_to_null_output_writes_nothing() { ... } void No_values_to_sufficient_output_writes_empty() { ... } void Positive_value_to_sufficient_output_writes_value_without_sign() { ... } void Negative_value_to_sufficient_output_writes_value_with_sign() { ... } void Value_to_insufficient_output_writes_truncated_value() { ... } void Multiple_values_to_sufficient_output_writes_comma_separated_values() { ... } void Multiple_values_to_insufficient_output_writes_truncated_value_sequence() { ... }
  • 40. size_t ints_to_csv( const int * to_write, size_t how_many, char * output, size_t length);  No values from null to null output writes nothing  Value to null output writes nothing  No values to sufficient output writes empty  Positive value to sufficient output writes value without sign  Negative value to sufficient output writes value with sign  Value to insufficient output writes truncated value  Multiple values to sufficient output writes comma separated values  Multiple values to insufficient output writes truncated value sequence
  • 41. Tests that are not written with their role as specifications in mind can be very confusing to read. The difficulty in understanding what they are testing can greatly reduce the velocity at which a codebase can be changed. Nat Pryce and Steve Freeman "Are Your Tests Really Driving Your Development?"
  • 42.
  • 43. Propositions are vehicles for stating how things are or might be.
  • 44. Thus only indicative sentences which it makes sense to think of as being true or as being false are capable of expressing propositions.
  • 45. public static bool IsLeapYear(int year) ...
  • 49. Make definite assertions. Avoid tame, colourless, hesitating, noncommittal language. Note [...] that when a sentence is made stronger, it usually becomes shorter. Thus brevity is a by-product of vigour. William Strunk and E B White The Elements of Style
  • 50.
  • 54. A test case should be just that: it should correspond to a single case.
  • 55. namespace Leap_year_spec { [TestFixture] public class A_year_is_a_leap_year { [Test] public void If_it_is_divisible_by_4_but_not_by_100()  [Test] public void If_it_is_divisible_by_400()  } [TestFixture] public class A_year_is_not_a_leap_year { [Test] public void If_it_is_not_divisible_by_4()  [Test] public void If_it_is_divisible_by_100_but_not_by_400()  } }
  • 56. namespace Leap_year_spec { [TestFixture] public class A_year_is_a_leap_year { [Test] public void If_it_is_divisible_by_4_but_not_by_100()  [Test] public void If_it_is_divisible_by_400()  } [TestFixture] public class A_year_is_not_a_leap_year { [Test] public void If_it_is_not_divisible_by_4()  [Test] public void If_it_is_divisible_by_100_but_not_by_400()  } }
  • 57. namespace Leap_year_spec { [TestFixture] public class A_year_is_a_leap_year { [Test] public void If_it_is_divisible_by_4_but_not_by_100()  [Test] public void If_it_is_divisible_by_400()  } [TestFixture] public class A_year_is_not_a_leap_year { [Test] public void If_it_is_not_divisible_by_4()  [Test] public void If_it_is_divisible_by_100_but_not_by_400()  } }
  • 58. namespace Leap_year_spec { [TestFixture] public class A_year_is_a_leap_year { [Test] public void If_it_is_divisible_by_4_but_not_by_100( [Values(2012, 1984, 4)] int year) { Assert.IsTrue(IsLeapYear(year)); } [Test] public void If_it_is_divisible_by_400( [Range(400, 2400, 400)] int year) { Assert.IsTrue(IsLeapYear(year)); } } [TestFixture] public class A_year_is_not_a_leap_year { [Test] public void If_it_is_not_divisible_by_4()  [Test] public void If_it_is_divisible_by_100_but_not_by_400()  } }
  • 59. namespace Leap_year_spec { [TestFixture] public class A_year_is_a_leap_year { [Test] public void If_it_is_divisible_by_4_but_not_by_100( [Values(2012, 1984, 4)] int year) { Assert.IsTrue(IsLeapYear(year)); } [Test] public void If_it_is_divisible_by_400( [Range(400, 2400, 400)] int year) { Assert.IsTrue(IsLeapYear(year)); } } [TestFixture] public class A_year_is_not_a_leap_year { [Test] public void If_it_is_not_divisible_by_4()  [Test] public void If_it_is_divisible_by_100_but_not_by_400()  } }
  • 60. namespace Leap_year_spec { [TestFixture] public class A_year_is_either_a_leap_year_or_not { [Test] public void IsLeapYear_is_correct([Range(1, 10000)] int year)  } }
  • 61. namespace Leap_year_spec { [TestFixture] public class A_year_is_either_a_leap_year_or_not { [Test] public void IsLeapYear_is_correct([Range(1, 10000)] int year) { Assert.AreEqual( year % 4 == 0 && year % 100 != 0 || year % 400 == 0, IsLeapYear(year)); } } }
  • 62. namespace Leap_year_spec { [TestFixture] public class A_year_is_either_a_leap_year_or_not { [Test] public void IsLeapYear_is_correct([Range(1, 10000)] int year) { Assert.AreEqual(LeapYearExpectation(year), IsLeapYear(year)); } public static bool LeapYearExpectation(int year) { return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; } } }
  • 63. public static bool IsLeapYear(int year) { return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; }
  • 64. All happy families are alike; each unhappy family is unhappy in its own way. Leo Tolstoy Anna Karenina
  • 65. proposition isbn_spec[] = { ... "Test validation", [] { CATCH(isbn("97805968094857"), isbn::malformed); CATCH(isbn("978059680948"), isbn::malformed); CATCH(isbn("978Q5968=9485"), isbn::malformed); CATCH(isbn("9780596809486"), isbn::malformed); }, ... };
  • 66. struct proposition { std::string name; std::function<void()> run; }; struct failure { const char * expression; int line; }; template<typename Propositions> void test(const Propositions & to_test) { for(auto & test : to_test) { try { std::cout << test.name << std::flush; test.run(); std::cout << "n"; } catch(failure & caught) { std::cout << " failed:n " << caught.expression << "n at line " << caught.line << "n"; } } } #define ASSERT(condition) void((condition) ? 0 : throw failure({ "ASSERT(" #condition ")", __LINE__ })) #define CATCH(expression, exception) try { (expression); throw failure({ "CATCH(" #expression ", " #exception ")", __LINE__ }); } catch (exception &) { } catch (...) { throw failure({ "CATCH(" #expression ", " #exception ")", __LINE__ }); }
  • 67. proposition isbn_spec[] = { ... "Test validation", [] { CATCH(isbn("97805968094857"), isbn::malformed); CATCH(isbn("978059680948"), isbn::malformed); CATCH(isbn("978Q5968=9485"), isbn::malformed); CATCH(isbn("9780596809486"), isbn::malformed); }, ... };
  • 68. proposition isbn_spec[] = { ... "Test validation", [] { CATCH(isbn("97805968094857"), isbn::malformed); CATCH(isbn("978059680948"), isbn::malformed); CATCH(isbn("978Q5968=9485"), isbn::malformed); CATCH(isbn("9780596809486"), isbn::malformed); }, ... };
  • 69. proposition isbn_spec[] = { ... "Test validation works", [] { CATCH(isbn("97805968094857"), isbn::malformed); CATCH(isbn("978059680948"), isbn::malformed); CATCH(isbn("978Q5968=9485"), isbn::malformed); CATCH(isbn("9780596809486"), isbn::malformed); }, ... };
  • 70. proposition isbn_spec[] = { ... "Test validation works", [] { CATCH(isbn("97805968094857"), isbn::malformed); CATCH(isbn("978059680948"), isbn::malformed); CATCH(isbn("978Q5968=9485"), isbn::malformed); CATCH(isbn("9780596809486"), isbn::malformed); }, ... };
  • 71. proposition isbn_spec[] = { ... "ISBNs with more than 13 digits are malformed", [] { CATCH(isbn("97805968094857"), isbn::malformed); }, "ISBNs with fewer than 13 digits are malformed", [] { CATCH(isbn("978059680948"), isbn::malformed); }, "ISBNs with non-digits are malformed", [] { CATCH(isbn("978Q5968=9485"), isbn::malformed); }, "ISBNs with an incorrect check digit are malformed", [] { CATCH(isbn("9780596809486"), isbn::malformed); }, ... };
  • 72. proposition isbn_spec[] = { ... "ISBNs with more than 13 digits are malformed", [] { CATCH(isbn("97805968094857"), isbn::malformed); }, "ISBNs with fewer than 13 digits are malformed", [] { CATCH(isbn("978059680948"), isbn::malformed); }, "ISBNs with non-digits are malformed", [] { CATCH(isbn("978Q5968=9485"), isbn::malformed); }, "ISBNs with an incorrect check digit are malformed", [] { CATCH(isbn("9780596809486"), isbn::malformed); }, ... };
  • 73. Validation is not a behaviour; the consequence of validation is.
  • 75. public class RecentlyUsedList { ... public RecentlyUsedList() ... public int Count { get... } public string this[int index] { get... } public void Add(string newItem) ... ... }
  • 76. [TestFixture] public class RecentlyUsedListTests { [Test] public void TestConstructor() ... [Test] public void TestCountGet() ... [Test] public void TestIndexerGet() ... [Test] public void TestAdd() ... ... }
  • 78. namespace RecentlyUsedList_spec { [TestFixture] public class A_new_list { [Test] public void Is_empty()  } [TestFixture] public class An_empty_list { [Test] public void Retains_a_single_addition()  [Test] public void Retains_unique_additions_in_stack_order()  } [TestFixture] public class A_non_empty_list { [Test] public void Is_unchanged_when_head_item_is_readded()  [Test] public void Moves_non_head_item_to_head_when_it_is_readded()  } [TestFixture] public class Any_list_rejects { [Test] public void Addition_of_null_items()  [Test] public void Indexing_past_its_end()  [Test] public void Negative_indexing()  } }
  • 79. namespace RecentlyUsedList_spec { [TestFixture] public class A_new_list { [Test] public void Is_empty()  } [TestFixture] public class An_empty_list { [Test] public void Retains_a_single_addition()  [Test] public void Retains_unique_additions_in_stack_order()  } [TestFixture] public class A_non_empty_list { [Test] public void Is_unchanged_when_head_item_is_readded()  [Test] public void Moves_non_head_item_to_head_when_it_is_readded()  } [TestFixture] public class Any_list_rejects { [Test] public void Addition_of_null_items()  [Test] public void Indexing_past_its_end()  [Test] public void Negative_indexing()  } }
  • 80. So who should you be writing the tests for? For the person trying to understand your code. Good tests act as documentation for the code they are testing. They describe how the code works. For each usage scenario, the test(s):  Describe the context, starting point, or preconditions that must be satisfied  Illustrate how the software is invoked  Describe the expected results or postconditions to be verified Different usage scenarios will have slightly different versions of each of these. Gerard Meszaros "Write Tests for People"
  • 81. namespace RecentlyUsedList_spec { [TestFixture] public class A_new_list ... [TestFixture] public class An_empty_list { [Test] public void Retains_a_single_addition( [Values("Oxford", "Bristol", "London")] string addend) { var items = new RecentlyUsedList(); // Given... items.Add(addend); // When... Assert.AreEqual(1, items.Count); // Then... Assert.AreEqual(addend, list[0]); } [Test] public void Retains_unique_additions_in_stack_order()  } [TestFixture] public class A_non_empty_list ... [TestFixture] public class Any_list_rejects ... }
  • 82. One of the things that Osherove warns against is multiple asserts in unit tests. Owen Pellegrin http://www.owenpellegrin.com/blog/testing/how-do-you-solve-multiple-asserts/
  • 83. Proper unit tests should fail for exactly one reason, that’s why you should be using one assert per unit test. http://rauchy.net/oapt/
  • 84. string[] itinerary = ...; string[] expected = { "London", "Bristol", "Oslo" }; Assert.AreEqual(expected, itinerary);
  • 85. Assert.IsNotNull(itinerary); Assert.AreEqual(3, itinerary.Length); Assert.AreEqual("London", itinerary[0]); Assert.AreEqual("Bristol", itinerary[1]); Assert.AreEqual("Oslo", itinerary[2]); Assert.DoesNotThrow(() => { string[] itinerary = ...; string[] expected = ...; });
  • 86.
  • 90. My guideline is usually that you test one logical concept per test. You can have multiple asserts on the same object. They will usually be the same concept being tested. Roy Osherove http://www.owenpellegrin.com/blog/testing/how-do-you-solve-multiple-asserts/
  • 91. One of the most foundational principles of good design is: Gather together those things that change for the same reason, and separate those things that change for different reasons. This principle is often known as the single responsibility principle, or SRP. In short, it says that a subsystem, module, class, or even a function, should not have more than one reason to change.
  • 93.
  • 94.
  • 95.
  • 96. A test is not a unit test if:  It talks to the database  It communicates across the network  It touches the file system  It can't run at the same time as any of your other unit tests  You have to do special things to your environment (such as editing config files) to run it. Tests that do these things aren't bad. Often they are worth writing, and they can be written in a unit test harness. However, it is important to be able to separate them from true unit tests so that we can keep a set of tests that we can run fast whenever we make our changes. Michael Feathers "A Set of Unit Testing Rules" http://www.artima.com/weblogs/viewpost.jsp?thread=126923
  • 97. A unit test is a test of behaviour whose success or failure is wholly determined by the correctness of the test and the correctness of the unit under test. Kevlin Henney http://www.theregister.co.uk/2007/07/28/what_are_your_units/
  • 98. Necessarily not unit testable, such as interactions with external dependencies Unit testable in practice Unit testable in theory, but not unit testable in practice
  • 99. Mutable Immutable Unshared Shared Unshared mutable data needs no synchronisation Unshared immutable data needs no synchronisation Shared mutable data needs synchronisation Shared immutable data needs no synchronisation
  • 100. Mutable Immutable Unshared Shared Unshared mutable data needs no synchronisation Unshared immutable data needs no synchronisation Shared mutable data needs synchronisation Shared immutable data needs no synchronisation The Synchronisation Quadrant
  • 101. The real value of tests is not that they detect bugs in the code but that they detect inadequacies in the methods, concentration, and skills of those who design and produce the code. C A R Hoare