Docstoc

RTC

Document Sample
RTC Powered By Docstoc
					Refactoring Test Code
       ³¯«Ø§ø
     2002/09/20
ctchen@ctchen.idv.tw
Reference
  Arie van Deursen et al., “Refactoring
  Test Code, ” XP 2001 Conference, 2001.
Outline
  Introduction
  Test Code Smells
  Refactorings
  Conclusion
Introduction
Why Refactoring Test Code
  The ideal test code / production code
  ratio approaches 1:1, it is not surprising
  that unit tests are begin refactored.
  Refactoring test code is different from
  refactoring production code:
    There is a distinct set of bad smells.
    Improving test code involves additional
    test-specific refactorings.
Unit Testing
   Unit testing is a technique at the heart of
   extreme programming (XP).
   A typical test for a particular method:
  1.   Code to set up the fixture.
  2.   The call of the method.
  3.   A comparison of the actual results with the.
       expected values.
  4.   Code to tear down the fixture.
   Tools support- xUnit.
Why so many tests?
  It helps the developers to overcome
  their fear for change:
    You don’t break anything.
  Problem:
    Changes in functionality will typically
    involve changes in the test code as well.
Test Code & Production Code

     Test
             verify    Production
     Code                 Code



                                    functionality changed




     Test
                 trace Production
     Code’               Code’
Refactoring
  Change the code without change the
  functionality of the system.
  How to do?
    A catalog of code smells.
    A wide range of refacorings.
  Refactoring test code:
    Test smells.
    Test refactorings.
Test Code Smells
Smell 1: Mystery Guest
  A test is no longer self contained if it uses
  external resources:
    There is not enough information to understand the
    tested functionality, making it hard to use it as
    documentation.
    Using external resources introduces hidden
    dependencies.
  Example:
  Solution:
    Inline Resource (1), Setup External Resource (2)
Smell 2: Resource Optimism
  Nondeterministic behavior may be occurred if
  a test code makes optimistic assumptions
  about the existence (or absence) and state of
  external resource.
    Tests run fine at one time and fail miserably the
    other time.
  Example:
  Solution:
    Setup External Resource (2)
Smell 3: Test Run War
  Tests run fine as long as you are the
  only one testing but fail when more
  programmers run them.
    This is most likely caused by resource
    interference.
  Example:
  Solution:
    Make Resource Unique (3)
Smell 4: General Fixture
  The setUp fixture is too general and different
  tests only access part of the fixture.
    It is harder to read and understand.
    It may make tests run more slowly.
  Example:
  Solution:
    Extract Method (F:110) with Inline Method (F:117),
    Extract Class (F:149).
Smell 5: Eager Test
  A test method checks several methods of the
  object to be tested
    It is hard to read and understand, and therefore
    more difficult to use as documentation.
    It makes tests more dependent on each other and
    harder to maintain.
  Example:
  Solution:
    Extract Method (F:110)
Smell 6: Lazy Test
  Several test methods check the same
  method using the same fixture.
    For example, check the values of different
    instance variables.
  Solution:
    Inline Method (F:117)
Smell 7: Assertion Roulette
  Having a number of assertions in a test
  method that have no explanation.
    If one of the assertions fails, you do not
    know which one it is.
  Example:
  Solution:
    Add Assertion Explanation (5)
Smell 8: Indirect Testing
  A test class contains methods that
  actually perform tests on other objects.
  Solution:
    Extract Method (F:110) & Move Method
    (F:142).
Smell 9: For Testers Only
  A production class contains methods
  that are only used by test methods,
  these methods either:
    Are not needed and can be removed, or
    Are only needed to set up a fixture for
    testing.
  Solution:
    Extract Subclass (F:330)
Smell 10: Sensitive Equality
  Writing equality checks by using the
  toString method.
    It may depend on many irrelevant details,
    such as commas, quotes, spaces, etc.
  Solution:
    Introduce Equality Method (6)
Smell 11: Test Code Duplication
  Test code may contain undesirable
  duplication.
    Duplication in the same test class.
    Duplication across test classes.
  Solution:
    Extract Method (F:110).
Refactorings
Refactoring 1:
Inline Resource (1/2)
  Incorporating the resource in the test
  code to remove the dependency
  between a test method and some
  external resource.
    Setting up a fixture in the test code that
    holds the same contents as the resource.
    A example of this is putting the contexts of
    a file that is used into some string in the
    test code.
Refactoring 1:
Inline Resource (2/2)
  If the contents of the resource are large:
    Suffering from Eager Test (5).
    Using Extract Method (F:110) or Reduce
    Date (4).
Refactoring 2:
Setup External Resource
  If it is necessary for a test to rely on
  external resource, such as directories,
  databases, or files:
    Explicitly creates or allocates these
    resources before testing.
    Releases them when done.
Refactoring 3:
Make Resource Unique
  A lot of problems originate from the use
  of overlapping resource name:
    Using unique identifiers for all resources
    that are allocated, for example:
      Time-stamp.
      GUID.
Refactoring 4: Reduce Data
  Minimize the data that is setup in
  fixtures to the bare essentials.
    It make them better suitable as
    documentation.
    Your tests will be less sensitive to changes.
Refactoring 5:
Add Assertion Explanation
  Assertions in the JUnit have an optional
  first argument to give an explanatory
  message to the user when the assertion
  fails.
    Using this message to distinguish between
    different assertions that occur in the same
    test.
Refactoring 6:
Introduce Equality Method
  If an object structure needs to be
  checked for equality in tests.
    Add an implementation for the “equals”
    method for the object’s class.
    Then rewrite the tests that use string
    equality to use the “equals” method.
Related Work
  Martin Fowler:
    Focuses on production code.
    Unit tests is to prove that a refactoring did not
    break anything.
    Unit test are used as documentation of the
    production code.
  Schneider:
    Describes how to prevent these smells right from
    the start by discussing a number of best practices
    for writing tests with JUnit.
Conclusion
  While working on the XP project, the authors
  observed that the quality of the test code was
  not as high as the production code.
  An open question: how test code refactoring
  interacts with the other XP practices?
  The precise interplay between test refactoring
  and the XP practices is a subject of the
  authors’ further research.
Q&A
Example- Smell 1:
Mystery Guest



           external resource
Example- Smell 2:
Resource Optimism


                    Do we have this file?
Example- Smell 3:
Test Run War
                    files may already exist
Example- Smell 4:
General Fixture
Example- Smell 5:
Eager Test

                    1




            2
Example- Smell 7:
Assertion Roulette
Example- Refactoring 1:
Inline Resource
Example- Refactoring 2:
Setup External Resource




                    explicitly creates resources




                     release them when done
Example- Refactoring 3:
Make Resource Unique




              or
Example- Refactoring (F:110):
Extract Method
Example- Refactoring (F:110):
Extract Method
Example- Refactoring 5:
Add Assertion Explanation

				
DOCUMENT INFO