SlideShare une entreprise Scribd logo
1  sur  82
Télécharger pour lire hors ligne
info@neueda.com
     01 498 0028
Programming with GUTs
   Writing Good Unit Tests


       Kevlin Henney
       kevlin@curbralan.com
Programming with GUTs
Intent
  Clarify the practice(s) of unit testing
Content
  Kinds of tests
  Testing approach
  Good unit tests
  Listening to your tests
But first...
Programming with GUTs
Programming with GUTs
Programming with GUTs
Programming with GUTs
Programming with GUTs
Kinds of Tests
Testing is a way of showing that you
care about something
 If a particular quality has value for a
 system, there should be a concrete
 demonstration of that value
 Code quality can be demonstrated
 through unit testing, static analysis,
 code reviews, analysing trends in
 defect and change history, etc.
Unit testing involves testing the individual
classes and mechanisms; is the
responsibility of the application engineer
who implemented the structure. [...]
System testing involves testing the system
as a whole; is the responsibility of the
quality assurance team.
                                                 Grady Booch
   Object-Oriented Analysis and Design with Applications, 2nd edition
System testing involves testing of the
software as a whole product
  System testing may be a distinct job or
  role, but not necessarily a group
Programmer testing involves testing
of code by programmers
  It is about code-facing tests, i.e., unit
  and integration tests
  It is not the testing of programmers!
Teams do deliver successfully using manual tests, so this
can't be considered a critical success factor. However, every
programmer I've interviewed who once moved to automated
tests swore never to work without them again. I find this
nothing short of astonishing.
Their reason has to do with improved quality of life. During
the week, they revise sections of code knowing they can
quickly check that they hadn't inadvertently broken
something along the way. When they get code working on
Friday, they go home knowing that they will be able on
Monday to detect whether anyone had broken it over the
weekend—they simply rerun the tests on Monday morning.
The tests give them freedom of movement during the day
and peace of mind at night.

                               Alistair Cockburn, Crystal Clear
Automated tests offer a way to
reduce the waste of repetitive work
 Write code that tests code
However, note that not all kinds of
tests can be automated
 Usability tests require observation and
 monitoring of real usage
 Exploratory testing is necessarily a
 manual task
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, quot;A Set of Unit Testing Rulesquot;
Unit tests are on code that is isolated
from external dependencies
  The outcome is based on the code of
  the test and the code under test
Integration tests involve external
dependencies
  Some portion of a system is necessarily
  not unit testable; the portion that is not
  necessarily so is a measure of coupling
It is worth distinguishing between
tests on functional behaviour...
 Written in terms of asserting values and
 interactions in response to use, the
 result of which is either right or wrong
And tests on operational behaviour
 More careful experimental design is
 needed because they typically require
 sampling and statistical interpretation
Testing Approach
If all you could make was a long-term argument for
testing, you could forget about it. Some people would do it
out of a sense of duty or because someone was watching
over their shoulder. As soon as the attention wavered or
the pressure increased, no new tests would get written,
the tests that were written wouldn't be run, and the whole
thing would fall apart.
                                                         Kent Beck
                         Extreme Programming Explained, 1st edition
Test Early.
Test Often.
Test Automatically.
            Andrew Hunt and David Thomas
                The Pragmatic Programmer
A passive approach looks at tests as
a way of confirming code behaviour
 This is Plain Ol' Unit Testing (POUTing)
An active approach also uses
testing to frame and review design
 This is Test-Driven Development (TDD)
A reactive approach introduces
tests in response to defects
 This is Defect-Driven Testing (DDT)
Very many people say quot;TDDquot; when
they really mean, quot;I have good unit
testsquot; (quot;I have GUTsquot;?) 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
quot;The modern programming professional has GUTsquot;
TDD complements other design,
verification and validation activities
  The emphasis is on defining a contract
  for a piece of code with behavioural
  examples that act as both specification
  and confirmation
  The act of writing tests (i.e., specifying)
  is interleaved with the act of writing the
  target code, offering both qualitative
  and quantitative feedback
Because Unit Testing is the plain-Jane
progenitor of Test Driven Development, it's
kind of unfair that it doesn't have an
acronym of its own. After all, it's hard to get
programmer types to pay attention if they
don't have some obscure jargon to bandy
about. [...] I'll borrow from the telco folks
and call unit testing Plain Old Unit Testing.
                 Jacob Proffitt, quot;TDD or POUTquot;
POUT employs testing as a code
verification tool
 Test writing follows code writing when
 the piece of target code is considered
 complete — effective POUTing
 assumes sooner rather than later
 The emphasis is quantitative and the
 focus is on defect discovery rather than
 design framing or problem clarification
DDT involves fixing a defect by first
adding a test for the defect
  DDT uses defects as an opportunity to
  improve coverage and embody
  learning from feedback in code form
  This is a normal part of effective TDD
  and POUT practice
  However, DDT can also be used on
  legacy code to grow the set of tests
Less unit testing dogma.
More unit testing karma.
                 Alberto Savoia
           quot;The Way of Testivusquot;
Good Unit Tests
I was using xUnit. I was using mock objects. So why did my tests seem
more like necessary baggage instead of this glorious, enabling
approach?
In order to resolve this mismatch, I decided to look more closely at
what was inspiring all the unit-testing euphoria. As I dug deeper, I
found some major flaws that had been fundamentally undermining my
approach to unit testing.
The first realization that jumped out at me was that my view of testing
was simply too “flat.” I looked at the unit-testing landscape and saw
tools and technologies. The programmer in me made unit testing more
about applying and exercising frameworks. It was as though I had
essentially reduced my concept of unit testing to the basic mechanics
of exercising xUnit to verify the behavior of my classes. [...]
In general, my mindset had me thinking far too narrowly about what it
meant to write good unit tests.
                         Tod Golding, quot;Tapping into Testing Nirvanaquot;
Poor unit tests lead to poor unit-
testing experiences
  Effective testing requires more than
  mastering the syntax of an assertion
It is all too easy to end up with
monolithic or ad hoc tests
  Rambling stream-of-consciousness
  narratives intended for machine
  execution but not human consumption
[Test]                                                [Test]
public void Test()                                    public void Test1()
{                                                     {
    RecentlyUsedList list = new RecentlyUsedList();       RecentlyUsedList list = new RecentlyUsedList();
    Assert.AreEqual(0, list.Count);                       Assert.AreEqual(0, list.Count);
    list.Add(quot;Aardvarkquot;);                                 list.Add(quot;Aardvarkquot;);
    Assert.AreEqual(1, list.Count);                       Assert.AreEqual(1, list.Count);
    Assert.AreEqual(quot;Aardvarkquot;, list[0]);                 Assert.AreEqual(quot;Aardvarkquot;, list[0]);
    list.Add(quot;Zebraquot;);                                    list.Add(quot;Zebraquot;);
    list.Add(quot;Mongoosequot;);                                 list.Add(quot;Mongoosequot;);
    Assert.AreEqual(3, list.Count);                       Assert.AreEqual(3, list.Count);
    Assert.AreEqual(quot;Mongoosequot;, list[0]);                 Assert.AreEqual(quot;Mongoosequot;, list[0]);
    Assert.AreEqual(quot;Zebraquot;, list[1]);                    Assert.AreEqual(quot;Zebraquot;, list[1]);
    Assert.AreEqual(quot;Aardvarkquot;, list[2]);                 Assert.AreEqual(quot;Aardvarkquot;, list[2]);
    list.Add(quot;Aardvarkquot;);                             }
    Assert.AreEqual(3, list.Count);                   [Test]
    Assert.AreEqual(quot;Aardvarkquot;, list[0]);             public void Test2()
    Assert.AreEqual(quot;Mongoosequot;, list[1]);             {
    Assert.AreEqual(quot;Zebraquot;, list[2]);                    RecentlyUsedList list = new RecentlyUsedList();
    bool thrown;                                          Assert.AreEqual(0, list.Count);
    try                                                   list.Add(quot;Aardvarkquot;);
    {                                                     Assert.AreEqual(1, list.Count);
        string unreachable = list[3];                     Assert.AreEqual(quot;Aardvarkquot;, list[0]);
        thrown = false;                                   list.Add(quot;Zebraquot;);
    }                                                     list.Add(quot;Mongoosequot;);
    catch (ArgumentOutOfRangeException)                   Assert.AreEqual(3, list.Count);
    {                                                     Assert.AreEqual(quot;Mongoosequot;, list[0]);
        thrown = true;                                    Assert.AreEqual(quot;Zebraquot;, list[1]);
    }                                                     Assert.AreEqual(quot;Aardvarkquot;, list[2]);
    Assert.IsTrue(thrown);                                list.Add(quot;Aardvarkquot;);
}                                                         Assert.AreEqual(3, list.Count);
                                                          Assert.AreEqual(quot;Aardvarkquot;, list[0]);
                                                          Assert.AreEqual(quot;Mongoosequot;, list[1]);
                                                          Assert.AreEqual(quot;Zebraquot;, list[2]);
                                                      }
                                                      [Test]
                                                      public void Test3()
                                                      {
                                                          RecentlyUsedList list = new RecentlyUsedList();
                                                          Assert.AreEqual(0, list.Count);
A predominantly procedural test
style is rarely effective
 It is based on the notion that quot;I have a
 function foo, therefore I have one test
 function that tests fooquot;, which does not
 really make sense for object usage
 And, in truth, procedural testing has
 never really made much sense for
 procedural code either
[Test]
public void Constructor()
                                                      Constructor
{
    RecentlyUsedList list = new RecentlyUsedList();
    Assert.AreEqual(0, list.Count);
}
[Test]
public void Add()
{
                                                         Add
    RecentlyUsedList list = new RecentlyUsedList();
    list.Add(quot;Aardvarkquot;);
    Assert.AreEqual(1, list.Count);
    list.Add(quot;Zebraquot;);
    list.Add(quot;Mongoosequot;);
    Assert.AreEqual(3, list.Count);
    list.Add(quot;Aardvarkquot;);
    Assert.AreEqual(3, list.Count);
}
[Test]
public void Indexer()
{
                                                        Indexer
    RecentlyUsedList list = new RecentlyUsedList();
    list.Add(quot;Aardvarkquot;);
    list.Add(quot;Zebraquot;);
    list.Add(quot;Mongoosequot;);
    Assert.AreEqual(quot;Mongoosequot;, list[0]);
    Assert.AreEqual(quot;Zebraquot;, list[1]);
    Assert.AreEqual(quot;Aardvarkquot;, list[2]);
    list.Add(quot;Aardvarkquot;);
    Assert.AreEqual(quot;Aardvarkquot;, list[0]);
    Assert.AreEqual(quot;Mongoosequot;, list[1]);
    Assert.AreEqual(quot;Zebraquot;, list[2]);
    bool thrown;
    try
    {
        string unreachable = list[3];
        thrown = false;
    }
    catch (ArgumentOutOfRangeException)
    {
        thrown = true;
    }
    Assert.IsTrue(thrown);
}
void test_sort()                                 void test_sort()
                                                 {
{
                                                     int empty[] = { 2, 1 };
    int single[] = { 2 };                            quickersort(empty + 1, 0);
    quickersort(single, 1);                          assert(empty[0] == 2);
    assert(sorted(single, 1));                       assert(empty[1] == 1);
                                                     int single[] = { 3, 2, 1 };
    int identical[] = { 2, 2, 2 };                   quickersort(single + 1, 1);
    quickersort(identical, 3);                       assert(single[0] == 3);
    assert(sorted(identical, 3));                    assert(single[1] == 2);
                                                     assert(single[2] == 1);
    int ascending[] = { -1, 0, 1 };
                                                     int identical[] = { 3, 2, 2, 2, 1 };
    quickersort(ascending, 3);                       quickersort(identical + 1, 3);
    assert(sorted(ascending, 3));                    assert(identical[0] == 3);
                                                     assert(identical[1] == 2);
    int descending[] = { 1, 0, -1 };                 assert(identical[2] == 2);
    quickersort(descending, 3);                      assert(identical[3] == 2);
    assert(sorted(descending, 3));                   assert(identical[4] == 1);
                                                     int ascending[] = { 2, -1, 0, 1, -2 };
    int arbitrary[] = { 32, 12, 19, INT_MIN };       quickersort(ascending + 1, 3);
    quickersort(arbitrary, 4);                       assert(ascending[0] == 2);
    assert(sorted(arbitrary, 4));                    assert(ascending[1] == -1);
                                                     assert(ascending[2] == 0);
}
                                                     assert(ascending[3] == 1);
                                                     assert(ascending[4] == -2);
                                                     int descending[] = { 2, 1, 0, -1, -2 };
                                                     quickersort(descending + 1, 3);
                                                     assert(descending[0] == 2);
                                                     assert(descending[1] == -1);
                                                     assert(descending[2] == 0);
                                                     assert(descending[3] == 1);
                                                     assert(descending[4] == -2);
                                                     int arbitrary[] = { 100, 32, 12, 19, INT_MIN, 0 };
                                                     quickersort(arbitrary + 1, 4);
                                                     assert(arbitrary[0] == 100);
                                                     assert(arbitrary[1] == INT_MIN);
                                                     assert(arbitrary[2] == 12);
                                                     assert(arbitrary[3] == 19);
                                                     assert(arbitrary[4] == 32);
                                                     assert(arbitrary[5] == 0);
                                                 }
Everybody knows that TDD stands for Test Driven Development.
However, people too often concentrate on the words quot;Testquot; and
quot;Developmentquot; and don't consider what the word quot;Drivenquot; really
implies. For tests to drive development they must do more than
just test that code performs its required functionality: they must
clearly express that required functionality to the reader. That is,
they must be clear specifications of the required functionality.
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
                quot;Are Your Tests Really Driving Your Development?quot;
Behavioural tests are based on
usage scenarios and outcomes
 They are purposeful, cutting across
 individual operations and reflecting use
 Tests are named in terms of
 requirements, emphasising intention
 and goals rather than mechanics
 This style correlates with the idea of use
 cases and user stories in the small
[Test]
public void InitialListIsEmpty()
{
                                                                                     Initial list is empty
    RecentlyUsedList list = new RecentlyUsedList();
    Assert.AreEqual(0, list.Count);
}
[Test]
public void AdditionOfSingleItemToEmptyListIsRetained()
                                                                                  Addition of single item to
{
    RecentlyUsedList list = new RecentlyUsedList();
                                                                                   empty list is retained
    list.Add(quot;Aardvarkquot;);
   Assert.AreEqual(1, list.Count);
   Assert.AreEqual(quot;Aardvarkquot;, list[0]);
}
[Test]
public void AdditionOfDistinctItemsIsRetainedInStackOrder()
                                                                                 Addition of distinct items is
{
    RecentlyUsedList list = new RecentlyUsedList();
                                                                                   retained in stack order
    list.Add(quot;Aardvarkquot;);
    list.Add(quot;Zebraquot;);
    list.Add(quot;Mongoosequot;);
   Assert.AreEqual(3, list.Count);
   Assert.AreEqual(quot;Mongoosequot;, list[0]);
   Assert.AreEqual(quot;Zebraquot;, list[1]);
   Assert.AreEqual(quot;Aardvarkquot;, list[2]);
}
[Test]
                                                                                 Duplicate items are moved to
public void DuplicateItemsAreMovedToFrontButNotAdded()
{
    RecentlyUsedList list = new RecentlyUsedList();
                                                                                     front but not added
    list.Add(quot;Aardvarkquot;);
    list.Add(quot;Mongoosequot;);
    list.Add(quot;Aardvarkquot;);
   Assert.AreEqual(2, list.Count);
   Assert.AreEqual(quot;Aardvarkquot;, list[0]);
   Assert.AreEqual(quot;Mongoosequot;, list[1]);
}
[Test, ExpectedException(ExceptionType = typeof(ArgumentOutOfRangeException))]
                                                                                  Out of range index throws
public void OutOfRangeIndexThrowsException()
{
    RecentlyUsedList list = new RecentlyUsedList();
                                                                                           exception
    list.Add(quot;Aardvarkquot;);
    list.Add(quot;Mongoosequot;);
    list.Add(quot;Aardvarkquot;);
    string unreachable = list[3];
}
void require_that_sorting_nothing_does_not_overrun()
{
    int empty[] = { 2, 1 };
                                                                 Require that sorting nothing does not overrun
    quickersort(empty + 1, 0);
    assert(empty[0] == 2);
    assert(empty[1] == 1);
}
void require_that_sorting_single_value_changes_nothing()
{
    int single[] = { 3, 2, 1 };
                                                                 Require that sorting single value changes nothing
    quickersort(single + 1, 1);
    assert(single[0] == 3);
    assert(single[1] == 2);
    assert(single[2] == 1);
}
void require_that_sorting_identical_value_changes_nothing()
{
    int identical[] = { 3, 2, 2, 2, 1 };
                                                                 Require that sorting identical values changes nothing
    quickersort(identical + 1, 3);
    assert(identical[0] == 3);
    assert(identical[1] == 2);
    assert(identical[2] == 2);
    assert(identical[3] == 2);
    assert(identical[4] == 1);
}
void require_that_sorting_ascending_sequence_changes_nothing()
{
    int ascending[] = { 2, -1, 0, 1, -2 };
                                                                 Require that sorting ascending sequence changes nothing
    quickersort(ascending + 1, 3);
    assert(ascending[0] == 2);
    assert(ascending[1] == -1);
    assert(ascending[2] == 0);
    assert(ascending[3] == 1);
    assert(ascending[4] == -2);
}
void require_that_sorting_descending_sequence_reverses_it()
{
                                                                 Require that sorting descending sequence reverses it
    int descending[] = { 2, 1, 0, -1, -2 };
    quickersort(descending + 1, 3);
    assert(descending[0] == 2);
    assert(descending[1] == -1);
    assert(descending[2] == 0);
    assert(descending[3] == 1);
    assert(descending[4] == -2);
}
void require_that_sorting_mixed_sequence_orders_it()
{
                                                                 Require that sorting mixed sequence orders it
    int arbitrary[] = { 100, 32, 12, 19, INT_MIN, 0 };
    quickersort(arbitrary + 1, 4);
    assert(arbitrary[0] == 100);
    assert(arbitrary[1] == INT_MIN);
    assert(arbitrary[2] == 12);
    assert(arbitrary[3] == 19);
    assert(arbitrary[4] == 32);
    assert(arbitrary[5] == 0);
}
public static boolean isLeapYear(int year)


Procedural test structured in terms of the function being tested,
but not in terms of its functionality:

testIsLeapYear


Tests partitioned in terms of the result of the function being tested:

testNonLeapYears
testLeapYears


Behavioural tests reflecting requirements and partitioned in terms
of the problem domain:

yearsNotDivisibleBy4AreNotLeapYears
                                                                          Increasingly
yearsDivisibleBy4ButNotBy100AreLeapYears
                                                                         expressive and
yearsDivisibleBy100ButNotBy400AreNotLeapYears
                                                                           sustainable
yearsDivisibleBy400AreLeapYears
It is common to name the characteristic or scenario being tested, but unless
the outcome is also described it is not obvious to see what the requirement is:

testYearsNotDivisibleBy4
testYearsDivisibleBy4
testYearsDivisibleBy100ButNotBy400
testYearsDivisibleBy400
A standard BDD practice is to use the word should in describing a behaviour.
This ritual word can sometimes be helpful if requirement-based naming is not
the norm, but be aware that it can sometimes look indecisive and uncommitted:

yearsNotDivisibleBy4ShouldNotBeLeapYears
yearsDivisibleBy4ButNotBy100ShouldBeLeapYears
yearsDivisibleBy100ButNotBy400ShouldNotBeLeapYears
yearsDivisibleBy400ShouldBeLeapYears
If using JUnit 3, or any other framework that expects a test prefix, consider
prefixing with testThat as, grammatically, it forces a complete sentence:

testThatYearsNotDivisibleBy4AreNotLeapYears
testThatYearsDivisibleBy4ButNotByAreLeapYears
testThatYearsDivisibleBy100ButNotBy400AreNotLeapYears
testThatYearsDivisibleBy400AreLeapYears
Example-based test cases are easy
to read and simple to write
 They have a linear narrative with a low
 cyclomatic complexity, and are
 therefore less tedious and error prone
 Coverage of critical cases is explicit
 Additional value coverage can be
 obtained using complementary and
 more exhaustive data-driven tests
public class CalculatorShellTest extends TestCase                    public class CalculatorShell
{                                                                    {
    public void testAdditionBasedOperations()                            public CalculatorShell(Reader input, Writer output)
    {                                                                    {
        assertEquals(quot;= 15quot;, run(quot;6n9nplusnquot;));                           this.input = new Scanner(input);
        assertEquals(quot;= 15quot;, run(quot;6n9n+nquot;));                              this.output = output;
        assertEquals(quot;= 10quot;, run(quot;27n17nminusnquot;));
        assertEquals(quot;= 10quot;, run(quot;27n17n-nquot;));                            commands.put(quot;dupquot;, quot;dupquot;);
        assertEquals(quot;= 12quot;, run(quot;3n4nmultiplynquot;));                       commands.put(quot;dropquot;, quot;dropquot;);
        assertEquals(quot;= 12quot;, run(quot;3n4n*nquot;));                              commands.put(quot;clearquot;, quot;clearquot;);
        assertEquals(quot;= -4quot;, run(quot;4nnegatenquot;));                            commands.put(quot;swapquot;, quot;swapquot;);
        assertEquals(quot;= 16quot;, run(quot;4nsquarenquot;));                            commands.put(quot;plusquot;, quot;plusquot;);
        assertEquals(quot;= 8quot;, run(quot;7n++nquot;));                                 commands.put(quot;+quot;, quot;plusquot;);
        assertEquals(quot;= 6quot;, run(quot;7n--nquot;));                                 commands.put(quot;minusquot;, quot;minusquot;);
    }                                                                        commands.put(quot;-quot;, quot;minusquot;);
    public void testDivisionBasedOperations()                                commands.put(quot;multiplyquot;, quot;multiplyquot;);
    {                                                                        commands.put(quot;*quot;, quot;multiplyquot;);
        assertEquals(quot;= 1quot;, run(quot;3n3ndivnquot;));                             commands.put(quot;divquot;, quot;divquot;);
        assertEquals(quot;= 1quot;, run(quot;4n3ndivnquot;));                             commands.put(quot;/quot;, quot;divquot;);
        assertEquals(quot;= 0quot;, run(quot;3n4ndivnquot;));                             commands.put(quot;modquot;, quot;modquot;);
        assertEquals(quot;= 0quot;, run(quot;3n0ndivnquot;));                             commands.put(quot;moduloquot;, quot;modquot;);
        assertEquals(quot;= 2quot;, run(quot;6n3n/nquot;));                               commands.put(quot;%quot;, quot;modquot;);
        assertEquals(quot;= 0quot;, run(quot;3n3nmodnquot;));                             commands.put(quot;negatequot;, quot;negatequot;);
        assertEquals(quot;= 1quot;, run(quot;4n3nmodnquot;));                             commands.put(quot;squarequot;, quot;squarequot;);
        assertEquals(quot;= 3quot;, run(quot;3n4nmodnquot;));                             commands.put(quot;++quot;, quot;incrementquot;);
        assertEquals(quot;= 0quot;, run(quot;3n0nmodnquot;));                             commands.put(quot;--quot;, quot;decrementquot;);
        assertEquals(quot;= 1quot;, run(quot;7n3n%nquot;));                               commands.put(quot;comparequot;, quot;comparequot;);
        assertEquals(quot;= 1quot;, run(quot;7n3nmodulonquot;));                      }
    }                                                                    public void run() throws IOException
    public void testComparisonOperation()                                {
    {                                                                        try
        assertEquals(quot;= 1quot;, run(quot;5n3ncomparenquot;));                         {
        assertEquals(quot;= 0quot;, run(quot;3n3ncomparenquot;));                              while(input.hasNextLine())
        assertEquals(quot;= -1quot;, run(quot;3n5ncomparenquot;));                             {
    }                                                                                                          String line = input.nextLine();
    public void testStackControlOperations()                                           if(line.length() == 0)
    {                                                                                  {
        assertEquals(quot;= 27 27quot;, run(quot;27ndupnquot;));                                          showStack();
        assertEquals(quot;= 17quot;, run(quot;17n27ndropnquot;));                                   }
        assertEquals(quot;=quot;, run(quot;9n6n17n27nclearnquot;));                               else
        assertEquals(quot;=quot;, run(quot;clearnquot;));                                             {
        assertEquals(quot;= 17 27quot;, run(quot;17n27nswapnquot;));                                     for(String token : line.split(quot;[ t]+quot;))
    }                                                                                           if(token.length() != 0)
    public void testStacking()                                                                      interpretToken(token);
    {                                                                                  }
        assertEquals(quot;=quot;, run(quot;nquot;));                                             }
        assertEquals(quot;= 4 3 2 1quot;, run(quot;1n2n3n4nnquot;));                    }
        assertEquals(quot;= 3 4 2 1quot;, run(quot;1n2n3n4nswapnquot;));                catch(Exit ignored)
        assertEquals(quot;= 7 2 1quot;, run(quot;1n2n3n4nplusnquot;));                  {
    }                                                                        }
    public void testSpaceSeparation()                                    }
    {                                                                    private void interpretToken(String token) throws IOException
        assertEquals(quot;= 4 3 2 1quot;, run(quot;1 2 3 4nnquot;));                   {
        assertEquals(quot;= 4 3 2 1quot;, run(quot; 1 2 3t4 nnquot;));                    try
        assertEquals(quot;= 3 4 2 1quot;, run(quot;1 2 3 4 swapnquot;));                    {
        assertEquals(quot;= 3 4 2 1quot;, run(quot;1 2 3n4 swap    nquot;));                    calculator.push(Integer.parseInt(token));
        assertEquals(quot;quot;, run(quot;1 2 3 exit nquot;));                              }
    }                                                                        catch(NumberFormatException ignored)
    public void testStackUnderflow()                                         {
    {                                                                             if(token.equals(quot;exitquot;))
        assertEquals(quot;Stack underflowquot;, run(quot;dropnquot;));                           {
        assertEquals(quot;Stack underflowquot;, run(quot;dupnquot;));                                 throw new Exit();
        assertEquals(quot;Stack underflowquot;, run(quot;negatenquot;));                         }
        assertEquals(quot;Stack underflowquot;, run(quot;1nswapnquot;));                        else
        assertEquals(quot;Stack underflowquot;, run(quot;1nplusnquot;));                        {
    }                                                                                  try
    public void testUnknownCommands()                                                  {
    {                                                                                       executeCommand(commands.get(token));
        assertEquals(quot;Unknown commandquot;, run(quot;dripnquot;));                                }
        assertEquals(quot;Unknown commandquot;, run(quot;1n2ndroopnquot;));                         catch(StackCalculator.UnderflowException caught)
    }                                                                                  {
    public void testExit()                                                                  output.write(quot;Stack underflownquot;);
    {                                                                                  }
        assertEquals(quot;quot;, run(quot;exitnquot;));                                               catch(UnknownCommand caught)
        assertEquals(quot;quot;, run(quot;6n9nexitnquot;));                                         {
        assertEquals(quot;quot;, run(quot;6n9nexitn17nquot;));                                          output.write(quot;Unknown commandnquot;);
        assertEquals(quot;quot;, run(quot;quot;));                                                     }
        assertEquals(quot;quot;, run(quot;6n9nquot;));                                          }
    }                                                                        }
    private static String run(String input)                              }
    {                                                                    private void executeCommand(String methodName) throws IOException
        Reader source = new StringReader(input);                         {
        Writer sink = new StringWriter();                                    if(methodName != null)
        CalculatorShell shell = new CalculatorShell(source, sink);           {
                                                                                  try
        try                                                                       {
        {                                                                              calculator.getClass().getMethod(methodName).invoke(calculator);
            shell.run();                                                               showStack();
        }                                                                         }
        catch(IOException caught)                                                 catch(InvocationTargetException caught)
        {                                                                         {
            throw new RuntimeException(caught);                                        throw (StackCalculator.UnderflowException) caught.getCause();
        }                                                                         }
                                                                                  catch(IllegalAccessException caught)
        return sink.toString().trim();                                            {
    }                                                                                  throw new UnknownCommand();
}                                                                                 }
                                                                                  catch(NoSuchMethodException caught)
                                                                                  {
                                                                                       throw new UnknownCommand();
                                                                                  }
                                                                             }
                                                                             else
                                                                             {
                                                                                  throw new UnknownCommand();
                                                                             }
                                                                         }
                                                                         private void showStack() throws IOException
                                                                         {
                                                                             String stack = quot;=quot;;
                                                                             for(int index = 0; index != calculator.depth(); ++index)
                                                                                  stack += quot; quot; + calculator.get(index);
                                                                             output.write(stack + quot;nquot;);
                                                                         }
                                                                     private StackCalculator calculator = new StackCalculator();
                                                                         private Map<String, String> commands = new HashMap<String, String>();
                                                                         private Scanner input;
                                                                         private Writer output;
                                                                     }
There are a number of things that
should appear in tests
 Simple cases, because you have to
 start somewhere
 Common cases, using equivalence
 partitioning to identify representatives
 Boundary cases, testing at and around
 Contractual error cases, i.e., test rainy-
 day as well as happy-day scenarios
There are a number of things that
should not appear in tests
 Do not assert on behaviours that are
 standard for the platform or language
 — the tests should be on your code
 Do not assert on implementation
 specifics — a comparison may return 1
 but test for > 0 — or incidental
 presentation — spacing, spelling, etc.
It is better to be roughly right than
precisely wrong.
                  John Maynard Keynes
The following is overcommitted and unnecessarily specific, hardwiring
incidental implementation details as requirements:


assertEquals(-1, lower.compareTo(higher));
assertEquals(0, value.compareTo(value));
assertEquals(+1, higher.compareTo(lower));

The following reflects the actual requirement, also making the intent clearer
by introducing specifically named custom assertions:


assertNegative(lower.compareTo(higher));
assertZero(value.compareTo(value));
assertPositive(higher.compareTo(lower));
Refactoring (noun): a change made to the
internal structure of software to make it
easier to understand and cheaper to modify
without changing its observable behavior.

Refactor (verb): to restructure software by
applying a series of refactorings without
changing the observable behavior of the
software.
                         Martin Fowler, Refactoring
public class RecentlyUsedList                          public class RecentlyUsedList
{                                                      {
    public RecentlyUsedList()                              public void Add(string newItem)
    {                                                      {
        list = new List<string>();                             list.Remove(newItem);
    }                                                          list.Add(newItem);
    public void Add(string newItem)                        }
    {                                                      public int Count
        if (list.Contains(newItem))                        {
        {                                                      get
            int position = list.IndexOf(newItem);              {
            string existingItem = list[position];                  return list.Count;
            list.RemoveAt(position);                           }
            list.Insert(0, existingItem);                  }
        }                                                  public string this[int index]
        else                                               {
        {                                                      get
            list.Insert(0, newItem);                           {
        }                                                          return list[Count - index - 1];
    }                                                          }
    public int Count                                       }
    {                                                      private List<string> list = new List<string>();
        get                                            }
        {
            int size = list.Count;
            return size;
        }
    }
    public string this[int index]
    {
        get
        {
            int position = 0;
            foreach (string value in list)
            {
                if (position == index)
                    return value;
                ++position;
            }
            throw new ArgumentOutOfRangeException();
        }
    }
    private List<string> list;
}
Functional



Operational




Developmental
class access_control
{
public:
    bool is_locked(const std::basic_string<char> &key) const
    {
        std::list<std::basic_string<char> >::const_iterator found = std::find(locked.begin(), locked.end(), key);
        return found != locked.end();
    }
    bool lock(const std::basic_string<char> &key)
    {
        std::list<std::basic_string<char> >::iterator found = std::find(locked.begin(), locked.end(), key);
        if(found == locked.end())
        {
            locked.insert(locked.end(), key);
            return true;
        }
        return false;
    }
    bool unlock(const std::basic_string<char> &key)
    {
        std::list<std::basic_string<char> >::iterator found = std::find(locked.begin(), locked.end(), key);
        if(found != locked.end())
        {
            locked.erase(found);
            return true;
        }
        return false;
    }
    ...
private:
    std::list<std::basic_string<char> > locked;
    ...
};
class access_control
{
public:
    bool is_locked(const std::string &key) const
    {
        return std::count(locked.begin(), locked.end(), key) != 0;
    }
    bool lock(const std::string &key)
    {
        if(is_locked(key))
        {
            return false;
        }
        else
        {
            locked.push_back(key);
            return true;
        }
    }
    bool unlock(const std::string &key)
    {
        const std::size_t old_size = locked.size();
        locked.remove(key);
        return locked.size() != old_size;
    }
    ...
private:
    std::list<std::string> locked;
    ...
};
class access_control
{
public:
    bool is_locked(const std::string &key) const
    {
        return locked.count(key) != 0;
    }
    bool lock(const std::string &key)
    {
        return locked.insert(key).second;
    }
    bool unlock(const std::string &key)
    {
        return locked.erase(key);
    }
    ...
private:
    std::set<std::string> locked;
    ...
};
Ideally, unit tests are black-box tests
  They should focus on interface contract
  They should not touch object internals
  or assume control structure in functions
White-box tests can end up testing
that the code does what it does
  They sometimes end up silencing
  opportunities for refactoring, as well as
  undermine attempts at refactoring
Listening to Your Tests
Tests and testability offer many forms
of feedback on code quality
 But you need to take care to listen (not
 just hear) and understand what it
 means and how to respond to it
 Don't solve symptoms — quot;Unit testing is
 boring/difficult/impossible, therefore
 don't do unit testingquot; — identify and
 resolve root causes — quot;Why is unit
 testing boring/difficult/impossible?quot;
•
              •




          •
       • • ••
           •


Consider a number of possible   Dependency inversion allows a design's
change scenarios and mark       dependencies to be reversed, loosened
affected components.            and manipulated at will, which means
                                that dependencies can be aligned with
                                known or anticipated stability.
Client                         Client




                                          Feature




Option A            Option B   Option A             Option B
B
A
                     ⊗
                         ⊗   C
        ⊗
                                 ⊗
                             ⊗



            D

            ⊗⊗⊗⊗             E

            ⊗ ⊗ ⊗⊗               ⊗


    F

            ⊗
Unit testability is a property of
loosely coupled code
  Inability to unit test a significant portion
  of the code base is an indication of
  dependency problems
  If only a small portion of the code is
  unit testable, it is likely that unit testing
  will not appear to be pulling its weight
  in contrast to, say, integration testing
Infrastructure
Plumbing and service
foundations introduced in
root layer of the hierarchy.



Services
Services adapted and
extended appropriately for
use by the domain classes.



Domain
Application domain concepts
modelled and represented
with respect to extension of
root infrastructure.
Domain                        Services            Infrastructure
Application domain            Services adapted    Plumbing and service
concepts modelled and         appropriately for   foundations for use
represented with respect      use by the domain   as self-contained
to plug-in services.          classes.            plug-ins.




                  concept

                realisation
Core   External
    Root
            Code   Wrapper

Wrapped




            Core     Usage
    Root
            Code   Interface




                   External
                   Wrapper
Decoupled
Name based on
Client
         implementation




         Implementation
              name




                                   Name based on
                          Client
                                    client usage




                                   Implementation
                                        name
There can be only one.
Unit testing also offers feedback on
code cohesion, and vice versa
 Overly complex behavioural objects
 that are essentially large slabs of
 procedural code
 Anaemic, underachieving objects that
 are plain ol' data structures in disguise
 Objects that are incompletely
 constructed and in need of validation
Don't ever invite a vampire
into your house, you silly boy.
   It renders you powerless.
[Test]
public void AdditionOfSingleItemToEmptyListIsRetained()
{
    RecentlyUsedList list = new RecentlyUsedList();
    list.List = new List<string>();
    list.Add(quot;Aardvarkquot;);
                                                              public class RecentlyUsedList
                                                              {
    Assert.AreEqual(1, list.List.Count);
    Assert.AreEqual(quot;Aardvarkquot;, list.List[0]);                    public void Add(string newItem)
}
                                                                  {
[Test]
                                                                      list.Remove(newItem);
public void AdditionOfDistinctItemsIsRetainedInStackOrder()
                                                                      list.Insert(0, newItem);
{
    RecentlyUsedList list = new RecentlyUsedList();
                                                                  }
    list.List = new List<string>();
                                                                  public List<string> List
    list.Add(quot;Aardvarkquot;);
                                                                  {
    list.Add(quot;Zebraquot;);
    list.Add(quot;Mongoosequot;);                                             get
                                                                      {
    Assert.AreEqual(3, list.List.Count);
                                                                          return list;
    Assert.AreEqual(quot;Mongoosequot;, list.List[0]);
                                                                      }
    Assert.AreEqual(quot;Zebraquot;, list.List[1]);
    Assert.AreEqual(quot;Aardvarkquot;, list.List[2]);                        set
}
                                                                      {
[Test]
                                                                          list = value;
public void DuplicateItemsAreMovedToFrontButNotAdded()
                                                                      }
{
    RecentlyUsedList list = new RecentlyUsedList();
                                                                  }
    list.List = new List<string>();
                                                                  private List<string> list;
    list.Add(quot;Aardvarkquot;);
                                                              }
    list.Add(quot;Mongoosequot;);
    list.Add(quot;Aardvarkquot;);

    Assert.AreEqual(2, list.List.Count);
    Assert.AreEqual(quot;Aardvarkquot;, list.List[0]);
    Assert.AreEqual(quot;Mongoosequot;, list.List[1]);
}
Programming with GUTs
public class Date
{
    ...
    public int getYear() ...
    public int getMonth() ...
    public int getDayInMonth() ...
    public void setYear(int newYear) ...
    public void setMonth(int newMonth) ...
    public void setDayInMonth(int newDayInMonth) ...
    ...
}
public class Date
{
    ...
    public int getYear() ...
    public int getMonth() ...
    public int getWeekInYear() ...
    public int getDayInYear() ...
    public int getDayInMonth() ...
    public int getDayInWeek() ...
    public void setYear(int newYear) ...
    public void setMonth(int newMonth) ...
    public void setWeekInYear(int newWeek) ...
    public void setDayInYear(int newDayInYear) ...
    public void setDayInMonth(int newDayInMonth) ...
    public void setDayInWeek(int newDayInWeek) ...
    ...
}
public class Date
{
    ...
    public int getYear() ...
    public int getMonth() ...
    public int getWeekInYear() ...
    public int getDayInYear() ...
    public int getDayInMonth() ...
    public int getDayInWeek() ...
    public void setYear(int newYear) ...
    public void setMonth(int newMonth) ...
    public void setWeekInYear(int newWeek) ...
    public void setDayInYear(int newDayInYear) ...
    public void setDayInMonth(int newDayInMonth) ...
    public void setDayInWeek(int newDayInWeek) ...
    ...
    private int year, month, dayInMonth;
}
public class Date
{
    ...
    public int getYear() ...
    public int getMonth() ...
    public int getWeekInYear() ...
    public int getDayInYear() ...
    public int getDayInMonth() ...
    public int getDayInWeek() ...
    public void setYear(int newYear) ...
    public void setMonth(int newMonth) ...
    public void setWeekInYear(int newWeek) ...
    public void setDayInYear(int newDayInYear) ...
    public void setDayInMonth(int newDayInMonth) ...
    public void setDayInWeek(int newDayInWeek) ...
    ...
    private int daysSinceEpoch;
}
When it is not necessary to change,
it is necessary not to change.

                       Lucius Cary
public class Date
{
    ...
    public int getYear() ...
    public int getMonth() ...
    public int getWeekInYear() ...
    public int getDayInYear() ...
    public int getDayInMonth() ...
    public int getDayInWeek() ...
    ...
}
public class Date
{
    ...
    public int year() ...
    public int month() ...
    public int weekInYear() ...
    public int dayInYear() ...
    public int dayInMonth() ...
    public int dayInWeek() ...
    ...
}
Be careful with coverage metrics
 Low coverage is always a warning sign
 Otherwise, understanding what kind of
 coverage is being discussed is key — is
 coverage according to statement,
 condition, path or value?
And be careful with coverage myths
 Without a context of execution, plain
 assertions in code offer no coverage
Watch out for misattribution
 If you have GUTs, but you fail to meet
 system requirements, the problem lies
 with system testing and managing
 requirements, not with unit testing
 If you don't know what to test, then how
 do you know what to code? Not
 knowing how to test is a separate issue
 addressed by learning and practice
Don't shoot the messenger
 If the bulk of testing occurs late in
 development, it is likely that unit testing
 will be difficult and will offer a poor ROI
 If TDD or pre-check-in POUTing is
 adopted for new code, but fewer
 defects are logged than with late
 testing on the old code, that is (1) good
 news and (2) unsurprising
If practice is unprincipled there is no coordination and there
is discord. When it is principled, there is balance, harmony
and union. Perhaps all life aspires to the condition of music.
                                                Aubrey Meyer

Contenu connexe

Tendances

Rik Teuben - Many Can Quarrel, Fewer Can Argue
Rik Teuben - Many Can Quarrel, Fewer Can Argue Rik Teuben - Many Can Quarrel, Fewer Can Argue
Rik Teuben - Many Can Quarrel, Fewer Can Argue TEST Huddle
 
Can we induce change with what we measure?
Can we induce change with what we measure?Can we induce change with what we measure?
Can we induce change with what we measure?Michaela Greiler
 
It Does What You Say, Not What You Mean: Lessons From A Decade of Program Repair
It Does What You Say, Not What You Mean: Lessons From A Decade of Program RepairIt Does What You Say, Not What You Mean: Lessons From A Decade of Program Repair
It Does What You Say, Not What You Mean: Lessons From A Decade of Program RepairClaire Le Goues
 
On the application of SAT solvers for Search Based Software Testing
On the application of SAT solvers for Search Based Software TestingOn the application of SAT solvers for Search Based Software Testing
On the application of SAT solvers for Search Based Software Testingjfrchicanog
 
[2017/2018] RESEARCH in software engineering
[2017/2018] RESEARCH in software engineering[2017/2018] RESEARCH in software engineering
[2017/2018] RESEARCH in software engineeringIvano Malavolta
 
'Continuous Quality Improvements – A Journey Through The Largest Scrum Projec...
'Continuous Quality Improvements – A Journey Through The Largest Scrum Projec...'Continuous Quality Improvements – A Journey Through The Largest Scrum Projec...
'Continuous Quality Improvements – A Journey Through The Largest Scrum Projec...TEST Huddle
 
Pareto-Optimal Search-Based Software Engineering (POSBSE): A Literature Survey
Pareto-Optimal Search-Based Software Engineering (POSBSE): A Literature SurveyPareto-Optimal Search-Based Software Engineering (POSBSE): A Literature Survey
Pareto-Optimal Search-Based Software Engineering (POSBSE): A Literature SurveyAbdel Salam Sayyad
 
Erik Boelen - Testing, The Next Level
Erik Boelen - Testing, The Next LevelErik Boelen - Testing, The Next Level
Erik Boelen - Testing, The Next LevelTEST Huddle
 
Search-based testing of procedural programs:iterative single-target or multi-...
Search-based testing of procedural programs:iterative single-target or multi-...Search-based testing of procedural programs:iterative single-target or multi-...
Search-based testing of procedural programs:iterative single-target or multi-...Vrije Universiteit Brussel
 
Lionel Briand ICSM 2011 Keynote
Lionel Briand ICSM 2011 KeynoteLionel Briand ICSM 2011 Keynote
Lionel Briand ICSM 2011 KeynoteICSM 2011
 
On Parameter Tuning in Search-Based Software Engineering: A Replicated Empiri...
On Parameter Tuning in Search-Based Software Engineering: A Replicated Empiri...On Parameter Tuning in Search-Based Software Engineering: A Replicated Empiri...
On Parameter Tuning in Search-Based Software Engineering: A Replicated Empiri...Abdel Salam Sayyad
 
Experiments on Design Pattern Discovery
Experiments on Design Pattern DiscoveryExperiments on Design Pattern Discovery
Experiments on Design Pattern DiscoveryTim Menzies
 
AUTOMATIC GENERATION AND OPTIMIZATION OF TEST DATA USING HARMONY SEARCH ALGOR...
AUTOMATIC GENERATION AND OPTIMIZATION OF TEST DATA USING HARMONY SEARCH ALGOR...AUTOMATIC GENERATION AND OPTIMIZATION OF TEST DATA USING HARMONY SEARCH ALGOR...
AUTOMATIC GENERATION AND OPTIMIZATION OF TEST DATA USING HARMONY SEARCH ALGOR...csandit
 
Interactive fault localization leveraging simple user feedback - by Liang Gong
Interactive fault localization leveraging simple user feedback - by Liang GongInteractive fault localization leveraging simple user feedback - by Liang Gong
Interactive fault localization leveraging simple user feedback - by Liang GongLiang Gong
 
Test Axioms – An Introduction
Test Axioms – An IntroductionTest Axioms – An Introduction
Test Axioms – An IntroductionPaul Gerrard
 

Tendances (20)

Rik Teuben - Many Can Quarrel, Fewer Can Argue
Rik Teuben - Many Can Quarrel, Fewer Can Argue Rik Teuben - Many Can Quarrel, Fewer Can Argue
Rik Teuben - Many Can Quarrel, Fewer Can Argue
 
Can we induce change with what we measure?
Can we induce change with what we measure?Can we induce change with what we measure?
Can we induce change with what we measure?
 
It Does What You Say, Not What You Mean: Lessons From A Decade of Program Repair
It Does What You Say, Not What You Mean: Lessons From A Decade of Program RepairIt Does What You Say, Not What You Mean: Lessons From A Decade of Program Repair
It Does What You Say, Not What You Mean: Lessons From A Decade of Program Repair
 
On the application of SAT solvers for Search Based Software Testing
On the application of SAT solvers for Search Based Software TestingOn the application of SAT solvers for Search Based Software Testing
On the application of SAT solvers for Search Based Software Testing
 
Ssbse12b.ppt
Ssbse12b.pptSsbse12b.ppt
Ssbse12b.ppt
 
Effective unit testing
Effective unit testingEffective unit testing
Effective unit testing
 
[2017/2018] RESEARCH in software engineering
[2017/2018] RESEARCH in software engineering[2017/2018] RESEARCH in software engineering
[2017/2018] RESEARCH in software engineering
 
'Continuous Quality Improvements – A Journey Through The Largest Scrum Projec...
'Continuous Quality Improvements – A Journey Through The Largest Scrum Projec...'Continuous Quality Improvements – A Journey Through The Largest Scrum Projec...
'Continuous Quality Improvements – A Journey Through The Largest Scrum Projec...
 
Software Testing
Software TestingSoftware Testing
Software Testing
 
Pareto-Optimal Search-Based Software Engineering (POSBSE): A Literature Survey
Pareto-Optimal Search-Based Software Engineering (POSBSE): A Literature SurveyPareto-Optimal Search-Based Software Engineering (POSBSE): A Literature Survey
Pareto-Optimal Search-Based Software Engineering (POSBSE): A Literature Survey
 
Erik Boelen - Testing, The Next Level
Erik Boelen - Testing, The Next LevelErik Boelen - Testing, The Next Level
Erik Boelen - Testing, The Next Level
 
Search-based testing of procedural programs:iterative single-target or multi-...
Search-based testing of procedural programs:iterative single-target or multi-...Search-based testing of procedural programs:iterative single-target or multi-...
Search-based testing of procedural programs:iterative single-target or multi-...
 
[Tho Quan] Fault Localization - Where is the root cause of a bug?
[Tho Quan] Fault Localization - Where is the root cause of a bug?[Tho Quan] Fault Localization - Where is the root cause of a bug?
[Tho Quan] Fault Localization - Where is the root cause of a bug?
 
Lionel Briand ICSM 2011 Keynote
Lionel Briand ICSM 2011 KeynoteLionel Briand ICSM 2011 Keynote
Lionel Briand ICSM 2011 Keynote
 
Dc35579583
Dc35579583Dc35579583
Dc35579583
 
On Parameter Tuning in Search-Based Software Engineering: A Replicated Empiri...
On Parameter Tuning in Search-Based Software Engineering: A Replicated Empiri...On Parameter Tuning in Search-Based Software Engineering: A Replicated Empiri...
On Parameter Tuning in Search-Based Software Engineering: A Replicated Empiri...
 
Experiments on Design Pattern Discovery
Experiments on Design Pattern DiscoveryExperiments on Design Pattern Discovery
Experiments on Design Pattern Discovery
 
AUTOMATIC GENERATION AND OPTIMIZATION OF TEST DATA USING HARMONY SEARCH ALGOR...
AUTOMATIC GENERATION AND OPTIMIZATION OF TEST DATA USING HARMONY SEARCH ALGOR...AUTOMATIC GENERATION AND OPTIMIZATION OF TEST DATA USING HARMONY SEARCH ALGOR...
AUTOMATIC GENERATION AND OPTIMIZATION OF TEST DATA USING HARMONY SEARCH ALGOR...
 
Interactive fault localization leveraging simple user feedback - by Liang Gong
Interactive fault localization leveraging simple user feedback - by Liang GongInteractive fault localization leveraging simple user feedback - by Liang Gong
Interactive fault localization leveraging simple user feedback - by Liang Gong
 
Test Axioms – An Introduction
Test Axioms – An IntroductionTest Axioms – An Introduction
Test Axioms – An Introduction
 

En vedette

Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015Codemotion
 
Bogotá 25 de enero de 2017
Bogotá 25 de enero de 2017Bogotá 25 de enero de 2017
Bogotá 25 de enero de 2017Casa de la Mujer
 
리눅스 드라이버 #2
리눅스 드라이버 #2리눅스 드라이버 #2
리눅스 드라이버 #2Sangho Park
 
Effect of pollution on fov (2)
Effect of pollution on fov (2)Effect of pollution on fov (2)
Effect of pollution on fov (2)Sharique Ahmad
 
Top 10 Things I Learned While Taking My Startup through a Silicon Valley Acce...
Top 10 Things I Learned While Taking My Startup through a Silicon Valley Acce...Top 10 Things I Learned While Taking My Startup through a Silicon Valley Acce...
Top 10 Things I Learned While Taking My Startup through a Silicon Valley Acce...Scott Salkin
 
Be Present and Productive: The 5 Gears of Life and Work
Be Present and Productive: The 5 Gears of Life and WorkBe Present and Productive: The 5 Gears of Life and Work
Be Present and Productive: The 5 Gears of Life and WorkWiley
 
cross compile
cross compilecross compile
cross compilehe4722
 
Robust and declarative machine learning pipelines for predictive buying at Ba...
Robust and declarative machine learning pipelines for predictive buying at Ba...Robust and declarative machine learning pipelines for predictive buying at Ba...
Robust and declarative machine learning pipelines for predictive buying at Ba...Gianmario Spacagna
 
KC Engineering Offers a Broad Range of Water Supply Services
KC Engineering Offers a Broad Range of Water Supply ServicesKC Engineering Offers a Broad Range of Water Supply Services
KC Engineering Offers a Broad Range of Water Supply ServicesErika Smith
 
Hugs and Disses: Valentine's Day Insights from Arc
Hugs and Disses: Valentine's Day Insights from ArcHugs and Disses: Valentine's Day Insights from Arc
Hugs and Disses: Valentine's Day Insights from ArcLeo Burnett
 
Anatomia de un módulo en drupal 8
Anatomia de un módulo en drupal 8Anatomia de un módulo en drupal 8
Anatomia de un módulo en drupal 8Javier Gomez
 
LODE Linking Open Descriptions of Events
LODE Linking Open Descriptions of EventsLODE Linking Open Descriptions of Events
LODE Linking Open Descriptions of EventsRaphael Troncy
 
Nanotechnology in civil engineering
Nanotechnology in civil engineeringNanotechnology in civil engineering
Nanotechnology in civil engineeringLakshmi K Suresh
 
Field Activity Planner for Oil & Gas
Field Activity Planner for Oil & GasField Activity Planner for Oil & Gas
Field Activity Planner for Oil & GasFutureOn
 
Agile Testing Dilemmas
Agile Testing DilemmasAgile Testing Dilemmas
Agile Testing DilemmasAman King
 
I Don't Hate You, I Just Hate Your Code
I Don't Hate You, I Just Hate Your CodeI Don't Hate You, I Just Hate Your Code
I Don't Hate You, I Just Hate Your CodeBrian Richards
 
INDIA HAS NEVER BEEN HERE BEFORE | Facts You Didn't Know About KG-D6
INDIA HAS NEVER BEEN HERE BEFORE | Facts You Didn't Know About KG-D6INDIA HAS NEVER BEEN HERE BEFORE | Facts You Didn't Know About KG-D6
INDIA HAS NEVER BEEN HERE BEFORE | Facts You Didn't Know About KG-D6Flame Of Truth
 

En vedette (19)

Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
 
Bogotá 25 de enero de 2017
Bogotá 25 de enero de 2017Bogotá 25 de enero de 2017
Bogotá 25 de enero de 2017
 
Unwinding The Twine
Unwinding The TwineUnwinding The Twine
Unwinding The Twine
 
리눅스 드라이버 #2
리눅스 드라이버 #2리눅스 드라이버 #2
리눅스 드라이버 #2
 
Effect of pollution on fov (2)
Effect of pollution on fov (2)Effect of pollution on fov (2)
Effect of pollution on fov (2)
 
Top 10 Things I Learned While Taking My Startup through a Silicon Valley Acce...
Top 10 Things I Learned While Taking My Startup through a Silicon Valley Acce...Top 10 Things I Learned While Taking My Startup through a Silicon Valley Acce...
Top 10 Things I Learned While Taking My Startup through a Silicon Valley Acce...
 
Be Present and Productive: The 5 Gears of Life and Work
Be Present and Productive: The 5 Gears of Life and WorkBe Present and Productive: The 5 Gears of Life and Work
Be Present and Productive: The 5 Gears of Life and Work
 
cross compile
cross compilecross compile
cross compile
 
Robust and declarative machine learning pipelines for predictive buying at Ba...
Robust and declarative machine learning pipelines for predictive buying at Ba...Robust and declarative machine learning pipelines for predictive buying at Ba...
Robust and declarative machine learning pipelines for predictive buying at Ba...
 
KC Engineering Offers a Broad Range of Water Supply Services
KC Engineering Offers a Broad Range of Water Supply ServicesKC Engineering Offers a Broad Range of Water Supply Services
KC Engineering Offers a Broad Range of Water Supply Services
 
Arduino presentacion
Arduino presentacionArduino presentacion
Arduino presentacion
 
Hugs and Disses: Valentine's Day Insights from Arc
Hugs and Disses: Valentine's Day Insights from ArcHugs and Disses: Valentine's Day Insights from Arc
Hugs and Disses: Valentine's Day Insights from Arc
 
Anatomia de un módulo en drupal 8
Anatomia de un módulo en drupal 8Anatomia de un módulo en drupal 8
Anatomia de un módulo en drupal 8
 
LODE Linking Open Descriptions of Events
LODE Linking Open Descriptions of EventsLODE Linking Open Descriptions of Events
LODE Linking Open Descriptions of Events
 
Nanotechnology in civil engineering
Nanotechnology in civil engineeringNanotechnology in civil engineering
Nanotechnology in civil engineering
 
Field Activity Planner for Oil & Gas
Field Activity Planner for Oil & GasField Activity Planner for Oil & Gas
Field Activity Planner for Oil & Gas
 
Agile Testing Dilemmas
Agile Testing DilemmasAgile Testing Dilemmas
Agile Testing Dilemmas
 
I Don't Hate You, I Just Hate Your Code
I Don't Hate You, I Just Hate Your CodeI Don't Hate You, I Just Hate Your Code
I Don't Hate You, I Just Hate Your Code
 
INDIA HAS NEVER BEEN HERE BEFORE | Facts You Didn't Know About KG-D6
INDIA HAS NEVER BEEN HERE BEFORE | Facts You Didn't Know About KG-D6INDIA HAS NEVER BEEN HERE BEFORE | Facts You Didn't Know About KG-D6
INDIA HAS NEVER BEEN HERE BEFORE | Facts You Didn't Know About KG-D6
 

Similaire à Programming with GUTs

An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development CodeOps Technologies LLP
 
assertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
assertYourself - Breaking the Theories and Assumptions of Unit Testing in FlexassertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
assertYourself - Breaking the Theories and Assumptions of Unit Testing in Flexmichael.labriola
 
Make good use of explortary testing
Make good use of explortary testingMake good use of explortary testing
Make good use of explortary testinggaoliang641
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven DevelopmentDhaval Dalal
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testingpleeps
 
SELJE_Database_Unit_Testing_Slides.pdf
SELJE_Database_Unit_Testing_Slides.pdfSELJE_Database_Unit_Testing_Slides.pdf
SELJE_Database_Unit_Testing_Slides.pdfEric Selje
 
Test analysis & design good practices@TDT Iasi 17Oct2013
Test analysis & design   good practices@TDT Iasi 17Oct2013Test analysis & design   good practices@TDT Iasi 17Oct2013
Test analysis & design good practices@TDT Iasi 17Oct2013Tabăra de Testare
 
DSR Testing (Part 1)
DSR Testing (Part 1)DSR Testing (Part 1)
DSR Testing (Part 1)Steve Upton
 
utPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLutPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLSteven Feuerstein
 
Unit and integration Testing
Unit and integration TestingUnit and integration Testing
Unit and integration TestingDavid Berliner
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentAll Things Open
 
Chapter 10 Testing and Quality Assurance1Unders.docx
Chapter 10 Testing and Quality Assurance1Unders.docxChapter 10 Testing and Quality Assurance1Unders.docx
Chapter 10 Testing and Quality Assurance1Unders.docxketurahhazelhurst
 

Similaire à Programming with GUTs (20)

An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development
 
TDD Best Practices
TDD Best PracticesTDD Best Practices
TDD Best Practices
 
Unit testing
Unit testingUnit testing
Unit testing
 
Why Unit Testingl
Why Unit TestinglWhy Unit Testingl
Why Unit Testingl
 
Why unit testingl
Why unit testinglWhy unit testingl
Why unit testingl
 
Why Unit Testingl
Why Unit TestinglWhy Unit Testingl
Why Unit Testingl
 
assertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
assertYourself - Breaking the Theories and Assumptions of Unit Testing in FlexassertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
assertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
 
Make good use of explortary testing
Make good use of explortary testingMake good use of explortary testing
Make good use of explortary testing
 
Unit testing - An introduction
Unit testing - An introductionUnit testing - An introduction
Unit testing - An introduction
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
Test Driven
Test DrivenTest Driven
Test Driven
 
SELJE_Database_Unit_Testing_Slides.pdf
SELJE_Database_Unit_Testing_Slides.pdfSELJE_Database_Unit_Testing_Slides.pdf
SELJE_Database_Unit_Testing_Slides.pdf
 
Unit Testing
Unit TestingUnit Testing
Unit Testing
 
Test analysis & design good practices@TDT Iasi 17Oct2013
Test analysis & design   good practices@TDT Iasi 17Oct2013Test analysis & design   good practices@TDT Iasi 17Oct2013
Test analysis & design good practices@TDT Iasi 17Oct2013
 
DSR Testing (Part 1)
DSR Testing (Part 1)DSR Testing (Part 1)
DSR Testing (Part 1)
 
utPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLutPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQL
 
Unit and integration Testing
Unit and integration TestingUnit and integration Testing
Unit and integration Testing
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
Chapter 10 Testing and Quality Assurance1Unders.docx
Chapter 10 Testing and Quality Assurance1Unders.docxChapter 10 Testing and Quality Assurance1Unders.docx
Chapter 10 Testing and Quality Assurance1Unders.docx
 

Plus de catherinewall

Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Enginecatherinewall
 
Building Modular Dynamic Web Apps Ben Hale
Building Modular Dynamic Web Apps   Ben HaleBuilding Modular Dynamic Web Apps   Ben Hale
Building Modular Dynamic Web Apps Ben Halecatherinewall
 
Infinispan The Future Of Os Data Grids Manik Surtani
Infinispan The Future Of Os Data Grids   Manik SurtaniInfinispan The Future Of Os Data Grids   Manik Surtani
Infinispan The Future Of Os Data Grids Manik Surtanicatherinewall
 
Java Future S Ritter
Java Future S RitterJava Future S Ritter
Java Future S Rittercatherinewall
 
Design Decisions for iPhone Applications, Des Traynor, Contrast
Design Decisions for iPhone Applications, Des Traynor, ContrastDesign Decisions for iPhone Applications, Des Traynor, Contrast
Design Decisions for iPhone Applications, Des Traynor, Contrastcatherinewall
 
Creating New Interaction with the iPhone, Daniel Heffernan, Appschool
Creating New Interaction with the iPhone, Daniel Heffernan, AppschoolCreating New Interaction with the iPhone, Daniel Heffernan, Appschool
Creating New Interaction with the iPhone, Daniel Heffernan, Appschoolcatherinewall
 
Ronan Geraghty Microsoft BizSpark Introduction
Ronan Geraghty Microsoft BizSpark IntroductionRonan Geraghty Microsoft BizSpark Introduction
Ronan Geraghty Microsoft BizSpark Introductioncatherinewall
 
Knocking on Heavens Door - The Business Reality of Doing Business in the Cloud
Knocking on Heavens Door - The Business Reality of Doing Business in the CloudKnocking on Heavens Door - The Business Reality of Doing Business in the Cloud
Knocking on Heavens Door - The Business Reality of Doing Business in the Cloudcatherinewall
 
Cloud Computing in Practice: Fast Application Development and Delivery on For...
Cloud Computing in Practice: Fast Application Development and Delivery on For...Cloud Computing in Practice: Fast Application Development and Delivery on For...
Cloud Computing in Practice: Fast Application Development and Delivery on For...catherinewall
 
Castles in the Cloud: Developing with Google App Engine
Castles in the Cloud: Developing with Google App EngineCastles in the Cloud: Developing with Google App Engine
Castles in the Cloud: Developing with Google App Enginecatherinewall
 
Emerging Technology in the Cloud! Real Life Examples. Pol Mac Aonghusa
Emerging Technology in the Cloud! Real Life Examples.  Pol Mac AonghusaEmerging Technology in the Cloud! Real Life Examples.  Pol Mac Aonghusa
Emerging Technology in the Cloud! Real Life Examples. Pol Mac Aonghusacatherinewall
 
How ICT will help deliver ESB\'s Sustainability Strategy, Padraig McManus, CE...
How ICT will help deliver ESB\'s Sustainability Strategy, Padraig McManus, CE...How ICT will help deliver ESB\'s Sustainability Strategy, Padraig McManus, CE...
How ICT will help deliver ESB\'s Sustainability Strategy, Padraig McManus, CE...catherinewall
 
Green Computing - A Leadership Role - Tom Moriarty, DELL
Green Computing - A Leadership Role - Tom Moriarty, DELLGreen Computing - A Leadership Role - Tom Moriarty, DELL
Green Computing - A Leadership Role - Tom Moriarty, DELLcatherinewall
 
Green IT @ STRATO - Rene Weinholtz
Green IT @ STRATO - Rene WeinholtzGreen IT @ STRATO - Rene Weinholtz
Green IT @ STRATO - Rene Weinholtzcatherinewall
 
The Business Challenges of the future Low Carbon Economy - Niall Brady
The Business Challenges of the future Low Carbon Economy - Niall BradyThe Business Challenges of the future Low Carbon Economy - Niall Brady
The Business Challenges of the future Low Carbon Economy - Niall Bradycatherinewall
 
The Electric Grid 2.0 - Fergus Wheatly
The Electric Grid 2.0 - Fergus WheatlyThe Electric Grid 2.0 - Fergus Wheatly
The Electric Grid 2.0 - Fergus Wheatlycatherinewall
 
SMART2020: ICT & Climate Change. Opportunities or Threat? Chris Tuppen, BT
SMART2020: ICT & Climate Change.  Opportunities or Threat? Chris Tuppen, BTSMART2020: ICT & Climate Change.  Opportunities or Threat? Chris Tuppen, BT
SMART2020: ICT & Climate Change. Opportunities or Threat? Chris Tuppen, BTcatherinewall
 
Green IT: Moving Beyond the 2% Solution - Doug Neal
Green IT: Moving Beyond the 2% Solution - Doug NealGreen IT: Moving Beyond the 2% Solution - Doug Neal
Green IT: Moving Beyond the 2% Solution - Doug Nealcatherinewall
 

Plus de catherinewall (20)

Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Engine
 
Building Modular Dynamic Web Apps Ben Hale
Building Modular Dynamic Web Apps   Ben HaleBuilding Modular Dynamic Web Apps   Ben Hale
Building Modular Dynamic Web Apps Ben Hale
 
Infinispan The Future Of Os Data Grids Manik Surtani
Infinispan The Future Of Os Data Grids   Manik SurtaniInfinispan The Future Of Os Data Grids   Manik Surtani
Infinispan The Future Of Os Data Grids Manik Surtani
 
Java Future S Ritter
Java Future S RitterJava Future S Ritter
Java Future S Ritter
 
Design Decisions for iPhone Applications, Des Traynor, Contrast
Design Decisions for iPhone Applications, Des Traynor, ContrastDesign Decisions for iPhone Applications, Des Traynor, Contrast
Design Decisions for iPhone Applications, Des Traynor, Contrast
 
Creating New Interaction with the iPhone, Daniel Heffernan, Appschool
Creating New Interaction with the iPhone, Daniel Heffernan, AppschoolCreating New Interaction with the iPhone, Daniel Heffernan, Appschool
Creating New Interaction with the iPhone, Daniel Heffernan, Appschool
 
Ronan Geraghty Microsoft BizSpark Introduction
Ronan Geraghty Microsoft BizSpark IntroductionRonan Geraghty Microsoft BizSpark Introduction
Ronan Geraghty Microsoft BizSpark Introduction
 
BackUpEarth
BackUpEarthBackUpEarth
BackUpEarth
 
Amazon Web Services
Amazon Web ServicesAmazon Web Services
Amazon Web Services
 
Knocking on Heavens Door - The Business Reality of Doing Business in the Cloud
Knocking on Heavens Door - The Business Reality of Doing Business in the CloudKnocking on Heavens Door - The Business Reality of Doing Business in the Cloud
Knocking on Heavens Door - The Business Reality of Doing Business in the Cloud
 
Cloud Computing in Practice: Fast Application Development and Delivery on For...
Cloud Computing in Practice: Fast Application Development and Delivery on For...Cloud Computing in Practice: Fast Application Development and Delivery on For...
Cloud Computing in Practice: Fast Application Development and Delivery on For...
 
Castles in the Cloud: Developing with Google App Engine
Castles in the Cloud: Developing with Google App EngineCastles in the Cloud: Developing with Google App Engine
Castles in the Cloud: Developing with Google App Engine
 
Emerging Technology in the Cloud! Real Life Examples. Pol Mac Aonghusa
Emerging Technology in the Cloud! Real Life Examples.  Pol Mac AonghusaEmerging Technology in the Cloud! Real Life Examples.  Pol Mac Aonghusa
Emerging Technology in the Cloud! Real Life Examples. Pol Mac Aonghusa
 
How ICT will help deliver ESB\'s Sustainability Strategy, Padraig McManus, CE...
How ICT will help deliver ESB\'s Sustainability Strategy, Padraig McManus, CE...How ICT will help deliver ESB\'s Sustainability Strategy, Padraig McManus, CE...
How ICT will help deliver ESB\'s Sustainability Strategy, Padraig McManus, CE...
 
Green Computing - A Leadership Role - Tom Moriarty, DELL
Green Computing - A Leadership Role - Tom Moriarty, DELLGreen Computing - A Leadership Role - Tom Moriarty, DELL
Green Computing - A Leadership Role - Tom Moriarty, DELL
 
Green IT @ STRATO - Rene Weinholtz
Green IT @ STRATO - Rene WeinholtzGreen IT @ STRATO - Rene Weinholtz
Green IT @ STRATO - Rene Weinholtz
 
The Business Challenges of the future Low Carbon Economy - Niall Brady
The Business Challenges of the future Low Carbon Economy - Niall BradyThe Business Challenges of the future Low Carbon Economy - Niall Brady
The Business Challenges of the future Low Carbon Economy - Niall Brady
 
The Electric Grid 2.0 - Fergus Wheatly
The Electric Grid 2.0 - Fergus WheatlyThe Electric Grid 2.0 - Fergus Wheatly
The Electric Grid 2.0 - Fergus Wheatly
 
SMART2020: ICT & Climate Change. Opportunities or Threat? Chris Tuppen, BT
SMART2020: ICT & Climate Change.  Opportunities or Threat? Chris Tuppen, BTSMART2020: ICT & Climate Change.  Opportunities or Threat? Chris Tuppen, BT
SMART2020: ICT & Climate Change. Opportunities or Threat? Chris Tuppen, BT
 
Green IT: Moving Beyond the 2% Solution - Doug Neal
Green IT: Moving Beyond the 2% Solution - Doug NealGreen IT: Moving Beyond the 2% Solution - Doug Neal
Green IT: Moving Beyond the 2% Solution - Doug Neal
 

Dernier

9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding TeamAdam Moalla
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxGDSC PJATK
 
Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Adtran
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAshyamraj55
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdfPedro Manuel
 
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfJamie (Taka) Wang
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-pyJamie (Taka) Wang
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.YounusS2
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesMd Hossain Ali
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPathCommunity
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesDavid Newbury
 
Comparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and IstioComparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and IstioChristian Posta
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Will Schroeder
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...DianaGray10
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Brian Pichman
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarPrecisely
 
Building AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxUdaiappa Ramachandran
 

Dernier (20)

9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptx
 
20230104 - machine vision
20230104 - machine vision20230104 - machine vision
20230104 - machine vision
 
Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdf
 
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-py
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation Developers
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond Ontologies
 
Comparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and IstioComparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and Istio
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )
 
201610817 - edge part1
201610817 - edge part1201610817 - edge part1
201610817 - edge part1
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
 
Building AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptx
 

Programming with GUTs

  • 1. info@neueda.com 01 498 0028
  • 2. Programming with GUTs Writing Good Unit Tests Kevlin Henney kevlin@curbralan.com
  • 4. Intent Clarify the practice(s) of unit testing Content Kinds of tests Testing approach Good unit tests Listening to your tests But first...
  • 11. Testing is a way of showing that you care about something If a particular quality has value for a system, there should be a concrete demonstration of that value Code quality can be demonstrated through unit testing, static analysis, code reviews, analysing trends in defect and change history, etc.
  • 12. Unit testing involves testing the individual classes and mechanisms; is the responsibility of the application engineer who implemented the structure. [...] System testing involves testing the system as a whole; is the responsibility of the quality assurance team. Grady Booch Object-Oriented Analysis and Design with Applications, 2nd edition
  • 13. System testing involves testing of the software as a whole product System testing may be a distinct job or role, but not necessarily a group Programmer testing involves testing of code by programmers It is about code-facing tests, i.e., unit and integration tests It is not the testing of programmers!
  • 14. Teams do deliver successfully using manual tests, so this can't be considered a critical success factor. However, every programmer I've interviewed who once moved to automated tests swore never to work without them again. I find this nothing short of astonishing. Their reason has to do with improved quality of life. During the week, they revise sections of code knowing they can quickly check that they hadn't inadvertently broken something along the way. When they get code working on Friday, they go home knowing that they will be able on Monday to detect whether anyone had broken it over the weekend—they simply rerun the tests on Monday morning. The tests give them freedom of movement during the day and peace of mind at night. Alistair Cockburn, Crystal Clear
  • 15. Automated tests offer a way to reduce the waste of repetitive work Write code that tests code However, note that not all kinds of tests can be automated Usability tests require observation and monitoring of real usage Exploratory testing is necessarily a manual task
  • 16. 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, quot;A Set of Unit Testing Rulesquot;
  • 17. Unit tests are on code that is isolated from external dependencies The outcome is based on the code of the test and the code under test Integration tests involve external dependencies Some portion of a system is necessarily not unit testable; the portion that is not necessarily so is a measure of coupling
  • 18. It is worth distinguishing between tests on functional behaviour... Written in terms of asserting values and interactions in response to use, the result of which is either right or wrong And tests on operational behaviour More careful experimental design is needed because they typically require sampling and statistical interpretation
  • 20. If all you could make was a long-term argument for testing, you could forget about it. Some people would do it out of a sense of duty or because someone was watching over their shoulder. As soon as the attention wavered or the pressure increased, no new tests would get written, the tests that were written wouldn't be run, and the whole thing would fall apart. Kent Beck Extreme Programming Explained, 1st edition
  • 21. Test Early. Test Often. Test Automatically. Andrew Hunt and David Thomas The Pragmatic Programmer
  • 22. A passive approach looks at tests as a way of confirming code behaviour This is Plain Ol' Unit Testing (POUTing) An active approach also uses testing to frame and review design This is Test-Driven Development (TDD) A reactive approach introduces tests in response to defects This is Defect-Driven Testing (DDT)
  • 23. Very many people say quot;TDDquot; when they really mean, quot;I have good unit testsquot; (quot;I have GUTsquot;?) 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 quot;The modern programming professional has GUTsquot;
  • 24. TDD complements other design, verification and validation activities The emphasis is on defining a contract for a piece of code with behavioural examples that act as both specification and confirmation The act of writing tests (i.e., specifying) is interleaved with the act of writing the target code, offering both qualitative and quantitative feedback
  • 25. Because Unit Testing is the plain-Jane progenitor of Test Driven Development, it's kind of unfair that it doesn't have an acronym of its own. After all, it's hard to get programmer types to pay attention if they don't have some obscure jargon to bandy about. [...] I'll borrow from the telco folks and call unit testing Plain Old Unit Testing. Jacob Proffitt, quot;TDD or POUTquot;
  • 26. POUT employs testing as a code verification tool Test writing follows code writing when the piece of target code is considered complete — effective POUTing assumes sooner rather than later The emphasis is quantitative and the focus is on defect discovery rather than design framing or problem clarification
  • 27. DDT involves fixing a defect by first adding a test for the defect DDT uses defects as an opportunity to improve coverage and embody learning from feedback in code form This is a normal part of effective TDD and POUT practice However, DDT can also be used on legacy code to grow the set of tests
  • 28. Less unit testing dogma. More unit testing karma. Alberto Savoia quot;The Way of Testivusquot;
  • 30. I was using xUnit. I was using mock objects. So why did my tests seem more like necessary baggage instead of this glorious, enabling approach? In order to resolve this mismatch, I decided to look more closely at what was inspiring all the unit-testing euphoria. As I dug deeper, I found some major flaws that had been fundamentally undermining my approach to unit testing. The first realization that jumped out at me was that my view of testing was simply too “flat.” I looked at the unit-testing landscape and saw tools and technologies. The programmer in me made unit testing more about applying and exercising frameworks. It was as though I had essentially reduced my concept of unit testing to the basic mechanics of exercising xUnit to verify the behavior of my classes. [...] In general, my mindset had me thinking far too narrowly about what it meant to write good unit tests. Tod Golding, quot;Tapping into Testing Nirvanaquot;
  • 31. Poor unit tests lead to poor unit- testing experiences Effective testing requires more than mastering the syntax of an assertion It is all too easy to end up with monolithic or ad hoc tests Rambling stream-of-consciousness narratives intended for machine execution but not human consumption
  • 32. [Test] [Test] public void Test() public void Test1() { { RecentlyUsedList list = new RecentlyUsedList(); RecentlyUsedList list = new RecentlyUsedList(); Assert.AreEqual(0, list.Count); Assert.AreEqual(0, list.Count); list.Add(quot;Aardvarkquot;); list.Add(quot;Aardvarkquot;); Assert.AreEqual(1, list.Count); Assert.AreEqual(1, list.Count); Assert.AreEqual(quot;Aardvarkquot;, list[0]); Assert.AreEqual(quot;Aardvarkquot;, list[0]); list.Add(quot;Zebraquot;); list.Add(quot;Zebraquot;); list.Add(quot;Mongoosequot;); list.Add(quot;Mongoosequot;); Assert.AreEqual(3, list.Count); Assert.AreEqual(3, list.Count); Assert.AreEqual(quot;Mongoosequot;, list[0]); Assert.AreEqual(quot;Mongoosequot;, list[0]); Assert.AreEqual(quot;Zebraquot;, list[1]); Assert.AreEqual(quot;Zebraquot;, list[1]); Assert.AreEqual(quot;Aardvarkquot;, list[2]); Assert.AreEqual(quot;Aardvarkquot;, list[2]); list.Add(quot;Aardvarkquot;); } Assert.AreEqual(3, list.Count); [Test] Assert.AreEqual(quot;Aardvarkquot;, list[0]); public void Test2() Assert.AreEqual(quot;Mongoosequot;, list[1]); { Assert.AreEqual(quot;Zebraquot;, list[2]); RecentlyUsedList list = new RecentlyUsedList(); bool thrown; Assert.AreEqual(0, list.Count); try list.Add(quot;Aardvarkquot;); { Assert.AreEqual(1, list.Count); string unreachable = list[3]; Assert.AreEqual(quot;Aardvarkquot;, list[0]); thrown = false; list.Add(quot;Zebraquot;); } list.Add(quot;Mongoosequot;); catch (ArgumentOutOfRangeException) Assert.AreEqual(3, list.Count); { Assert.AreEqual(quot;Mongoosequot;, list[0]); thrown = true; Assert.AreEqual(quot;Zebraquot;, list[1]); } Assert.AreEqual(quot;Aardvarkquot;, list[2]); Assert.IsTrue(thrown); list.Add(quot;Aardvarkquot;); } Assert.AreEqual(3, list.Count); Assert.AreEqual(quot;Aardvarkquot;, list[0]); Assert.AreEqual(quot;Mongoosequot;, list[1]); Assert.AreEqual(quot;Zebraquot;, list[2]); } [Test] public void Test3() { RecentlyUsedList list = new RecentlyUsedList(); Assert.AreEqual(0, list.Count);
  • 33. A predominantly procedural test style is rarely effective It is based on the notion that quot;I have a function foo, therefore I have one test function that tests fooquot;, which does not really make sense for object usage And, in truth, procedural testing has never really made much sense for procedural code either
  • 34. [Test] public void Constructor() Constructor { RecentlyUsedList list = new RecentlyUsedList(); Assert.AreEqual(0, list.Count); } [Test] public void Add() { Add RecentlyUsedList list = new RecentlyUsedList(); list.Add(quot;Aardvarkquot;); Assert.AreEqual(1, list.Count); list.Add(quot;Zebraquot;); list.Add(quot;Mongoosequot;); Assert.AreEqual(3, list.Count); list.Add(quot;Aardvarkquot;); Assert.AreEqual(3, list.Count); } [Test] public void Indexer() { Indexer RecentlyUsedList list = new RecentlyUsedList(); list.Add(quot;Aardvarkquot;); list.Add(quot;Zebraquot;); list.Add(quot;Mongoosequot;); Assert.AreEqual(quot;Mongoosequot;, list[0]); Assert.AreEqual(quot;Zebraquot;, list[1]); Assert.AreEqual(quot;Aardvarkquot;, list[2]); list.Add(quot;Aardvarkquot;); Assert.AreEqual(quot;Aardvarkquot;, list[0]); Assert.AreEqual(quot;Mongoosequot;, list[1]); Assert.AreEqual(quot;Zebraquot;, list[2]); bool thrown; try { string unreachable = list[3]; thrown = false; } catch (ArgumentOutOfRangeException) { thrown = true; } Assert.IsTrue(thrown); }
  • 35. void test_sort() void test_sort() { { int empty[] = { 2, 1 }; int single[] = { 2 }; quickersort(empty + 1, 0); quickersort(single, 1); assert(empty[0] == 2); assert(sorted(single, 1)); assert(empty[1] == 1); int single[] = { 3, 2, 1 }; int identical[] = { 2, 2, 2 }; quickersort(single + 1, 1); quickersort(identical, 3); assert(single[0] == 3); assert(sorted(identical, 3)); assert(single[1] == 2); assert(single[2] == 1); int ascending[] = { -1, 0, 1 }; int identical[] = { 3, 2, 2, 2, 1 }; quickersort(ascending, 3); quickersort(identical + 1, 3); assert(sorted(ascending, 3)); assert(identical[0] == 3); assert(identical[1] == 2); int descending[] = { 1, 0, -1 }; assert(identical[2] == 2); quickersort(descending, 3); assert(identical[3] == 2); assert(sorted(descending, 3)); assert(identical[4] == 1); int ascending[] = { 2, -1, 0, 1, -2 }; int arbitrary[] = { 32, 12, 19, INT_MIN }; quickersort(ascending + 1, 3); quickersort(arbitrary, 4); assert(ascending[0] == 2); assert(sorted(arbitrary, 4)); assert(ascending[1] == -1); assert(ascending[2] == 0); } assert(ascending[3] == 1); assert(ascending[4] == -2); int descending[] = { 2, 1, 0, -1, -2 }; quickersort(descending + 1, 3); assert(descending[0] == 2); assert(descending[1] == -1); assert(descending[2] == 0); assert(descending[3] == 1); assert(descending[4] == -2); int arbitrary[] = { 100, 32, 12, 19, INT_MIN, 0 }; quickersort(arbitrary + 1, 4); assert(arbitrary[0] == 100); assert(arbitrary[1] == INT_MIN); assert(arbitrary[2] == 12); assert(arbitrary[3] == 19); assert(arbitrary[4] == 32); assert(arbitrary[5] == 0); }
  • 36. Everybody knows that TDD stands for Test Driven Development. However, people too often concentrate on the words quot;Testquot; and quot;Developmentquot; and don't consider what the word quot;Drivenquot; really implies. For tests to drive development they must do more than just test that code performs its required functionality: they must clearly express that required functionality to the reader. That is, they must be clear specifications of the required functionality. 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 quot;Are Your Tests Really Driving Your Development?quot;
  • 37. Behavioural tests are based on usage scenarios and outcomes They are purposeful, cutting across individual operations and reflecting use Tests are named in terms of requirements, emphasising intention and goals rather than mechanics This style correlates with the idea of use cases and user stories in the small
  • 38. [Test] public void InitialListIsEmpty() { Initial list is empty RecentlyUsedList list = new RecentlyUsedList(); Assert.AreEqual(0, list.Count); } [Test] public void AdditionOfSingleItemToEmptyListIsRetained() Addition of single item to { RecentlyUsedList list = new RecentlyUsedList(); empty list is retained list.Add(quot;Aardvarkquot;); Assert.AreEqual(1, list.Count); Assert.AreEqual(quot;Aardvarkquot;, list[0]); } [Test] public void AdditionOfDistinctItemsIsRetainedInStackOrder() Addition of distinct items is { RecentlyUsedList list = new RecentlyUsedList(); retained in stack order list.Add(quot;Aardvarkquot;); list.Add(quot;Zebraquot;); list.Add(quot;Mongoosequot;); Assert.AreEqual(3, list.Count); Assert.AreEqual(quot;Mongoosequot;, list[0]); Assert.AreEqual(quot;Zebraquot;, list[1]); Assert.AreEqual(quot;Aardvarkquot;, list[2]); } [Test] Duplicate items are moved to public void DuplicateItemsAreMovedToFrontButNotAdded() { RecentlyUsedList list = new RecentlyUsedList(); front but not added list.Add(quot;Aardvarkquot;); list.Add(quot;Mongoosequot;); list.Add(quot;Aardvarkquot;); Assert.AreEqual(2, list.Count); Assert.AreEqual(quot;Aardvarkquot;, list[0]); Assert.AreEqual(quot;Mongoosequot;, list[1]); } [Test, ExpectedException(ExceptionType = typeof(ArgumentOutOfRangeException))] Out of range index throws public void OutOfRangeIndexThrowsException() { RecentlyUsedList list = new RecentlyUsedList(); exception list.Add(quot;Aardvarkquot;); list.Add(quot;Mongoosequot;); list.Add(quot;Aardvarkquot;); string unreachable = list[3]; }
  • 39. void require_that_sorting_nothing_does_not_overrun() { int empty[] = { 2, 1 }; Require that sorting nothing does not overrun quickersort(empty + 1, 0); assert(empty[0] == 2); assert(empty[1] == 1); } void require_that_sorting_single_value_changes_nothing() { int single[] = { 3, 2, 1 }; Require that sorting single value changes nothing quickersort(single + 1, 1); assert(single[0] == 3); assert(single[1] == 2); assert(single[2] == 1); } void require_that_sorting_identical_value_changes_nothing() { int identical[] = { 3, 2, 2, 2, 1 }; Require that sorting identical values changes nothing quickersort(identical + 1, 3); assert(identical[0] == 3); assert(identical[1] == 2); assert(identical[2] == 2); assert(identical[3] == 2); assert(identical[4] == 1); } void require_that_sorting_ascending_sequence_changes_nothing() { int ascending[] = { 2, -1, 0, 1, -2 }; Require that sorting ascending sequence changes nothing quickersort(ascending + 1, 3); assert(ascending[0] == 2); assert(ascending[1] == -1); assert(ascending[2] == 0); assert(ascending[3] == 1); assert(ascending[4] == -2); } void require_that_sorting_descending_sequence_reverses_it() { Require that sorting descending sequence reverses it int descending[] = { 2, 1, 0, -1, -2 }; quickersort(descending + 1, 3); assert(descending[0] == 2); assert(descending[1] == -1); assert(descending[2] == 0); assert(descending[3] == 1); assert(descending[4] == -2); } void require_that_sorting_mixed_sequence_orders_it() { Require that sorting mixed sequence orders it int arbitrary[] = { 100, 32, 12, 19, INT_MIN, 0 }; quickersort(arbitrary + 1, 4); assert(arbitrary[0] == 100); assert(arbitrary[1] == INT_MIN); assert(arbitrary[2] == 12); assert(arbitrary[3] == 19); assert(arbitrary[4] == 32); assert(arbitrary[5] == 0); }
  • 40. public static boolean isLeapYear(int year) Procedural test structured in terms of the function being tested, but not in terms of its functionality: testIsLeapYear Tests partitioned in terms of the result of the function being tested: testNonLeapYears testLeapYears Behavioural tests reflecting requirements and partitioned in terms of the problem domain: yearsNotDivisibleBy4AreNotLeapYears Increasingly yearsDivisibleBy4ButNotBy100AreLeapYears expressive and yearsDivisibleBy100ButNotBy400AreNotLeapYears sustainable yearsDivisibleBy400AreLeapYears
  • 41. It is common to name the characteristic or scenario being tested, but unless the outcome is also described it is not obvious to see what the requirement is: testYearsNotDivisibleBy4 testYearsDivisibleBy4 testYearsDivisibleBy100ButNotBy400 testYearsDivisibleBy400
  • 42. A standard BDD practice is to use the word should in describing a behaviour. This ritual word can sometimes be helpful if requirement-based naming is not the norm, but be aware that it can sometimes look indecisive and uncommitted: yearsNotDivisibleBy4ShouldNotBeLeapYears yearsDivisibleBy4ButNotBy100ShouldBeLeapYears yearsDivisibleBy100ButNotBy400ShouldNotBeLeapYears yearsDivisibleBy400ShouldBeLeapYears
  • 43. If using JUnit 3, or any other framework that expects a test prefix, consider prefixing with testThat as, grammatically, it forces a complete sentence: testThatYearsNotDivisibleBy4AreNotLeapYears testThatYearsDivisibleBy4ButNotByAreLeapYears testThatYearsDivisibleBy100ButNotBy400AreNotLeapYears testThatYearsDivisibleBy400AreLeapYears
  • 44. Example-based test cases are easy to read and simple to write They have a linear narrative with a low cyclomatic complexity, and are therefore less tedious and error prone Coverage of critical cases is explicit Additional value coverage can be obtained using complementary and more exhaustive data-driven tests
  • 45. public class CalculatorShellTest extends TestCase public class CalculatorShell { { public void testAdditionBasedOperations() public CalculatorShell(Reader input, Writer output) { { assertEquals(quot;= 15quot;, run(quot;6n9nplusnquot;)); this.input = new Scanner(input); assertEquals(quot;= 15quot;, run(quot;6n9n+nquot;)); this.output = output; assertEquals(quot;= 10quot;, run(quot;27n17nminusnquot;)); assertEquals(quot;= 10quot;, run(quot;27n17n-nquot;)); commands.put(quot;dupquot;, quot;dupquot;); assertEquals(quot;= 12quot;, run(quot;3n4nmultiplynquot;)); commands.put(quot;dropquot;, quot;dropquot;); assertEquals(quot;= 12quot;, run(quot;3n4n*nquot;)); commands.put(quot;clearquot;, quot;clearquot;); assertEquals(quot;= -4quot;, run(quot;4nnegatenquot;)); commands.put(quot;swapquot;, quot;swapquot;); assertEquals(quot;= 16quot;, run(quot;4nsquarenquot;)); commands.put(quot;plusquot;, quot;plusquot;); assertEquals(quot;= 8quot;, run(quot;7n++nquot;)); commands.put(quot;+quot;, quot;plusquot;); assertEquals(quot;= 6quot;, run(quot;7n--nquot;)); commands.put(quot;minusquot;, quot;minusquot;); } commands.put(quot;-quot;, quot;minusquot;); public void testDivisionBasedOperations() commands.put(quot;multiplyquot;, quot;multiplyquot;); { commands.put(quot;*quot;, quot;multiplyquot;); assertEquals(quot;= 1quot;, run(quot;3n3ndivnquot;)); commands.put(quot;divquot;, quot;divquot;); assertEquals(quot;= 1quot;, run(quot;4n3ndivnquot;)); commands.put(quot;/quot;, quot;divquot;); assertEquals(quot;= 0quot;, run(quot;3n4ndivnquot;)); commands.put(quot;modquot;, quot;modquot;); assertEquals(quot;= 0quot;, run(quot;3n0ndivnquot;)); commands.put(quot;moduloquot;, quot;modquot;); assertEquals(quot;= 2quot;, run(quot;6n3n/nquot;)); commands.put(quot;%quot;, quot;modquot;); assertEquals(quot;= 0quot;, run(quot;3n3nmodnquot;)); commands.put(quot;negatequot;, quot;negatequot;); assertEquals(quot;= 1quot;, run(quot;4n3nmodnquot;)); commands.put(quot;squarequot;, quot;squarequot;); assertEquals(quot;= 3quot;, run(quot;3n4nmodnquot;)); commands.put(quot;++quot;, quot;incrementquot;); assertEquals(quot;= 0quot;, run(quot;3n0nmodnquot;)); commands.put(quot;--quot;, quot;decrementquot;); assertEquals(quot;= 1quot;, run(quot;7n3n%nquot;)); commands.put(quot;comparequot;, quot;comparequot;); assertEquals(quot;= 1quot;, run(quot;7n3nmodulonquot;)); } } public void run() throws IOException public void testComparisonOperation() { { try assertEquals(quot;= 1quot;, run(quot;5n3ncomparenquot;)); { assertEquals(quot;= 0quot;, run(quot;3n3ncomparenquot;)); while(input.hasNextLine()) assertEquals(quot;= -1quot;, run(quot;3n5ncomparenquot;)); { } String line = input.nextLine(); public void testStackControlOperations() if(line.length() == 0) { { assertEquals(quot;= 27 27quot;, run(quot;27ndupnquot;)); showStack(); assertEquals(quot;= 17quot;, run(quot;17n27ndropnquot;)); } assertEquals(quot;=quot;, run(quot;9n6n17n27nclearnquot;)); else assertEquals(quot;=quot;, run(quot;clearnquot;)); { assertEquals(quot;= 17 27quot;, run(quot;17n27nswapnquot;)); for(String token : line.split(quot;[ t]+quot;)) } if(token.length() != 0) public void testStacking() interpretToken(token); { } assertEquals(quot;=quot;, run(quot;nquot;)); } assertEquals(quot;= 4 3 2 1quot;, run(quot;1n2n3n4nnquot;)); } assertEquals(quot;= 3 4 2 1quot;, run(quot;1n2n3n4nswapnquot;)); catch(Exit ignored) assertEquals(quot;= 7 2 1quot;, run(quot;1n2n3n4nplusnquot;)); { } } public void testSpaceSeparation() } { private void interpretToken(String token) throws IOException assertEquals(quot;= 4 3 2 1quot;, run(quot;1 2 3 4nnquot;)); { assertEquals(quot;= 4 3 2 1quot;, run(quot; 1 2 3t4 nnquot;)); try assertEquals(quot;= 3 4 2 1quot;, run(quot;1 2 3 4 swapnquot;)); { assertEquals(quot;= 3 4 2 1quot;, run(quot;1 2 3n4 swap nquot;)); calculator.push(Integer.parseInt(token)); assertEquals(quot;quot;, run(quot;1 2 3 exit nquot;)); } } catch(NumberFormatException ignored) public void testStackUnderflow() { { if(token.equals(quot;exitquot;)) assertEquals(quot;Stack underflowquot;, run(quot;dropnquot;)); { assertEquals(quot;Stack underflowquot;, run(quot;dupnquot;)); throw new Exit(); assertEquals(quot;Stack underflowquot;, run(quot;negatenquot;)); } assertEquals(quot;Stack underflowquot;, run(quot;1nswapnquot;)); else assertEquals(quot;Stack underflowquot;, run(quot;1nplusnquot;)); { } try public void testUnknownCommands() { { executeCommand(commands.get(token)); assertEquals(quot;Unknown commandquot;, run(quot;dripnquot;)); } assertEquals(quot;Unknown commandquot;, run(quot;1n2ndroopnquot;)); catch(StackCalculator.UnderflowException caught) } { public void testExit() output.write(quot;Stack underflownquot;); { } assertEquals(quot;quot;, run(quot;exitnquot;)); catch(UnknownCommand caught) assertEquals(quot;quot;, run(quot;6n9nexitnquot;)); { assertEquals(quot;quot;, run(quot;6n9nexitn17nquot;)); output.write(quot;Unknown commandnquot;); assertEquals(quot;quot;, run(quot;quot;)); } assertEquals(quot;quot;, run(quot;6n9nquot;)); } } } private static String run(String input) } { private void executeCommand(String methodName) throws IOException Reader source = new StringReader(input); { Writer sink = new StringWriter(); if(methodName != null) CalculatorShell shell = new CalculatorShell(source, sink); { try try { { calculator.getClass().getMethod(methodName).invoke(calculator); shell.run(); showStack(); } } catch(IOException caught) catch(InvocationTargetException caught) { { throw new RuntimeException(caught); throw (StackCalculator.UnderflowException) caught.getCause(); } } catch(IllegalAccessException caught) return sink.toString().trim(); { } throw new UnknownCommand(); } } catch(NoSuchMethodException caught) { throw new UnknownCommand(); } } else { throw new UnknownCommand(); } } private void showStack() throws IOException { String stack = quot;=quot;; for(int index = 0; index != calculator.depth(); ++index) stack += quot; quot; + calculator.get(index); output.write(stack + quot;nquot;); } private StackCalculator calculator = new StackCalculator(); private Map<String, String> commands = new HashMap<String, String>(); private Scanner input; private Writer output; }
  • 46. There are a number of things that should appear in tests Simple cases, because you have to start somewhere Common cases, using equivalence partitioning to identify representatives Boundary cases, testing at and around Contractual error cases, i.e., test rainy- day as well as happy-day scenarios
  • 47. There are a number of things that should not appear in tests Do not assert on behaviours that are standard for the platform or language — the tests should be on your code Do not assert on implementation specifics — a comparison may return 1 but test for > 0 — or incidental presentation — spacing, spelling, etc.
  • 48. It is better to be roughly right than precisely wrong. John Maynard Keynes
  • 49. The following is overcommitted and unnecessarily specific, hardwiring incidental implementation details as requirements: assertEquals(-1, lower.compareTo(higher)); assertEquals(0, value.compareTo(value)); assertEquals(+1, higher.compareTo(lower)); The following reflects the actual requirement, also making the intent clearer by introducing specifically named custom assertions: assertNegative(lower.compareTo(higher)); assertZero(value.compareTo(value)); assertPositive(higher.compareTo(lower));
  • 50. Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior. Refactor (verb): to restructure software by applying a series of refactorings without changing the observable behavior of the software. Martin Fowler, Refactoring
  • 51. public class RecentlyUsedList public class RecentlyUsedList { { public RecentlyUsedList() public void Add(string newItem) { { list = new List<string>(); list.Remove(newItem); } list.Add(newItem); public void Add(string newItem) } { public int Count if (list.Contains(newItem)) { { get int position = list.IndexOf(newItem); { string existingItem = list[position]; return list.Count; list.RemoveAt(position); } list.Insert(0, existingItem); } } public string this[int index] else { { get list.Insert(0, newItem); { } return list[Count - index - 1]; } } public int Count } { private List<string> list = new List<string>(); get } { int size = list.Count; return size; } } public string this[int index] { get { int position = 0; foreach (string value in list) { if (position == index) return value; ++position; } throw new ArgumentOutOfRangeException(); } } private List<string> list; }
  • 53. class access_control { public: bool is_locked(const std::basic_string<char> &key) const { std::list<std::basic_string<char> >::const_iterator found = std::find(locked.begin(), locked.end(), key); return found != locked.end(); } bool lock(const std::basic_string<char> &key) { std::list<std::basic_string<char> >::iterator found = std::find(locked.begin(), locked.end(), key); if(found == locked.end()) { locked.insert(locked.end(), key); return true; } return false; } bool unlock(const std::basic_string<char> &key) { std::list<std::basic_string<char> >::iterator found = std::find(locked.begin(), locked.end(), key); if(found != locked.end()) { locked.erase(found); return true; } return false; } ... private: std::list<std::basic_string<char> > locked; ... };
  • 54. class access_control { public: bool is_locked(const std::string &key) const { return std::count(locked.begin(), locked.end(), key) != 0; } bool lock(const std::string &key) { if(is_locked(key)) { return false; } else { locked.push_back(key); return true; } } bool unlock(const std::string &key) { const std::size_t old_size = locked.size(); locked.remove(key); return locked.size() != old_size; } ... private: std::list<std::string> locked; ... };
  • 55. class access_control { public: bool is_locked(const std::string &key) const { return locked.count(key) != 0; } bool lock(const std::string &key) { return locked.insert(key).second; } bool unlock(const std::string &key) { return locked.erase(key); } ... private: std::set<std::string> locked; ... };
  • 56. Ideally, unit tests are black-box tests They should focus on interface contract They should not touch object internals or assume control structure in functions White-box tests can end up testing that the code does what it does They sometimes end up silencing opportunities for refactoring, as well as undermine attempts at refactoring
  • 58. Tests and testability offer many forms of feedback on code quality But you need to take care to listen (not just hear) and understand what it means and how to respond to it Don't solve symptoms — quot;Unit testing is boring/difficult/impossible, therefore don't do unit testingquot; — identify and resolve root causes — quot;Why is unit testing boring/difficult/impossible?quot;
  • 59. • • • • •• • Consider a number of possible Dependency inversion allows a design's change scenarios and mark dependencies to be reversed, loosened affected components. and manipulated at will, which means that dependencies can be aligned with known or anticipated stability.
  • 60. Client Client Feature Option A Option B Option A Option B
  • 61. B A ⊗ ⊗ C ⊗ ⊗ ⊗ D ⊗⊗⊗⊗ E ⊗ ⊗ ⊗⊗ ⊗ F ⊗
  • 62. Unit testability is a property of loosely coupled code Inability to unit test a significant portion of the code base is an indication of dependency problems If only a small portion of the code is unit testable, it is likely that unit testing will not appear to be pulling its weight in contrast to, say, integration testing
  • 63. Infrastructure Plumbing and service foundations introduced in root layer of the hierarchy. Services Services adapted and extended appropriately for use by the domain classes. Domain Application domain concepts modelled and represented with respect to extension of root infrastructure.
  • 64. Domain Services Infrastructure Application domain Services adapted Plumbing and service concepts modelled and appropriately for foundations for use represented with respect use by the domain as self-contained to plug-in services. classes. plug-ins. concept realisation
  • 65. Core External Root Code Wrapper Wrapped Core Usage Root Code Interface External Wrapper Decoupled
  • 66. Name based on Client implementation Implementation name Name based on Client client usage Implementation name
  • 67. There can be only one.
  • 68. Unit testing also offers feedback on code cohesion, and vice versa Overly complex behavioural objects that are essentially large slabs of procedural code Anaemic, underachieving objects that are plain ol' data structures in disguise Objects that are incompletely constructed and in need of validation
  • 69. Don't ever invite a vampire into your house, you silly boy. It renders you powerless.
  • 70. [Test] public void AdditionOfSingleItemToEmptyListIsRetained() { RecentlyUsedList list = new RecentlyUsedList(); list.List = new List<string>(); list.Add(quot;Aardvarkquot;); public class RecentlyUsedList { Assert.AreEqual(1, list.List.Count); Assert.AreEqual(quot;Aardvarkquot;, list.List[0]); public void Add(string newItem) } { [Test] list.Remove(newItem); public void AdditionOfDistinctItemsIsRetainedInStackOrder() list.Insert(0, newItem); { RecentlyUsedList list = new RecentlyUsedList(); } list.List = new List<string>(); public List<string> List list.Add(quot;Aardvarkquot;); { list.Add(quot;Zebraquot;); list.Add(quot;Mongoosequot;); get { Assert.AreEqual(3, list.List.Count); return list; Assert.AreEqual(quot;Mongoosequot;, list.List[0]); } Assert.AreEqual(quot;Zebraquot;, list.List[1]); Assert.AreEqual(quot;Aardvarkquot;, list.List[2]); set } { [Test] list = value; public void DuplicateItemsAreMovedToFrontButNotAdded() } { RecentlyUsedList list = new RecentlyUsedList(); } list.List = new List<string>(); private List<string> list; list.Add(quot;Aardvarkquot;); } list.Add(quot;Mongoosequot;); list.Add(quot;Aardvarkquot;); Assert.AreEqual(2, list.List.Count); Assert.AreEqual(quot;Aardvarkquot;, list.List[0]); Assert.AreEqual(quot;Mongoosequot;, list.List[1]); }
  • 72. public class Date { ... public int getYear() ... public int getMonth() ... public int getDayInMonth() ... public void setYear(int newYear) ... public void setMonth(int newMonth) ... public void setDayInMonth(int newDayInMonth) ... ... }
  • 73. public class Date { ... public int getYear() ... public int getMonth() ... public int getWeekInYear() ... public int getDayInYear() ... public int getDayInMonth() ... public int getDayInWeek() ... public void setYear(int newYear) ... public void setMonth(int newMonth) ... public void setWeekInYear(int newWeek) ... public void setDayInYear(int newDayInYear) ... public void setDayInMonth(int newDayInMonth) ... public void setDayInWeek(int newDayInWeek) ... ... }
  • 74. public class Date { ... public int getYear() ... public int getMonth() ... public int getWeekInYear() ... public int getDayInYear() ... public int getDayInMonth() ... public int getDayInWeek() ... public void setYear(int newYear) ... public void setMonth(int newMonth) ... public void setWeekInYear(int newWeek) ... public void setDayInYear(int newDayInYear) ... public void setDayInMonth(int newDayInMonth) ... public void setDayInWeek(int newDayInWeek) ... ... private int year, month, dayInMonth; }
  • 75. public class Date { ... public int getYear() ... public int getMonth() ... public int getWeekInYear() ... public int getDayInYear() ... public int getDayInMonth() ... public int getDayInWeek() ... public void setYear(int newYear) ... public void setMonth(int newMonth) ... public void setWeekInYear(int newWeek) ... public void setDayInYear(int newDayInYear) ... public void setDayInMonth(int newDayInMonth) ... public void setDayInWeek(int newDayInWeek) ... ... private int daysSinceEpoch; }
  • 76. When it is not necessary to change, it is necessary not to change. Lucius Cary
  • 77. public class Date { ... public int getYear() ... public int getMonth() ... public int getWeekInYear() ... public int getDayInYear() ... public int getDayInMonth() ... public int getDayInWeek() ... ... }
  • 78. public class Date { ... public int year() ... public int month() ... public int weekInYear() ... public int dayInYear() ... public int dayInMonth() ... public int dayInWeek() ... ... }
  • 79. Be careful with coverage metrics Low coverage is always a warning sign Otherwise, understanding what kind of coverage is being discussed is key — is coverage according to statement, condition, path or value? And be careful with coverage myths Without a context of execution, plain assertions in code offer no coverage
  • 80. Watch out for misattribution If you have GUTs, but you fail to meet system requirements, the problem lies with system testing and managing requirements, not with unit testing If you don't know what to test, then how do you know what to code? Not knowing how to test is a separate issue addressed by learning and practice
  • 81. Don't shoot the messenger If the bulk of testing occurs late in development, it is likely that unit testing will be difficult and will offer a poor ROI If TDD or pre-check-in POUTing is adopted for new code, but fewer defects are logged than with late testing on the old code, that is (1) good news and (2) unsurprising
  • 82. If practice is unprincipled there is no coordination and there is discord. When it is principled, there is balance, harmony and union. Perhaps all life aspires to the condition of music. Aubrey Meyer