refactoring test codectchen/pdf/rtc.pdf · why refactoring test code the ideal test code /...

Post on 16-Oct-2020

13 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Refactoring Test Code

陳建村

2002/09/20ctchen@ctchen.idv.tw

Reference

Arie van Deursen et al., “RefactoringTest Code, ” XP 2001 Conference, 2001.

Outline

IntroductionTest Code SmellsRefactoringsConclusion

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

TestCode

ProductionCode

verify

TestCode’

ProductionCode’

trace

functionality changed

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, orAre 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

2

1

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

top related