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

45
Refactoring Test Code 陳建村 2002/09/20 [email protected]

Upload: others

Post on 16-Oct-2020

12 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Refactoring Test Codectchen/pdf/RTC.pdf · 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

陳建村

2002/09/[email protected]

Page 2: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Reference

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

Page 3: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Outline

IntroductionTest Code SmellsRefactoringsConclusion

Page 4: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Introduction

Page 5: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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.

Page 6: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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.

Page 7: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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.

Page 8: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Test Code & Production Code

TestCode

ProductionCode

verify

TestCode’

ProductionCode’

trace

functionality changed

Page 9: Refactoring Test Codectchen/pdf/RTC.pdf · 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

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.

Page 10: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Test Code Smells

Page 11: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored
Page 12: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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)

Page 13: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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)

Page 14: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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)

Page 15: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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).

Page 16: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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)

Page 17: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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)

Page 18: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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)

Page 19: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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).

Page 20: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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)

Page 21: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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)

Page 22: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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).

Page 23: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Refactorings

Page 24: Refactoring Test Codectchen/pdf/RTC.pdf · 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 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.

Page 25: Refactoring Test Codectchen/pdf/RTC.pdf · 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 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).

Page 26: Refactoring Test Codectchen/pdf/RTC.pdf · 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 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.

Page 27: Refactoring Test Codectchen/pdf/RTC.pdf · 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 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.

Page 28: Refactoring Test Codectchen/pdf/RTC.pdf · 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 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.

Page 29: Refactoring Test Codectchen/pdf/RTC.pdf · 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 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.

Page 30: Refactoring Test Codectchen/pdf/RTC.pdf · 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 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.

Page 31: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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.

Page 32: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

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.

Page 33: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Q&A

Page 34: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Smell 1: Mystery Guest

external resource

Page 35: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Smell 2: Resource Optimism

Do we have this file?

Page 36: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Smell 3: Test Run War

files may already exist

Page 37: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Smell 4: General Fixture

Page 38: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Smell 5: Eager Test

2

1

Page 39: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Smell 7: Assertion Roulette

Page 40: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Refactoring 1: Inline Resource

Page 41: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Refactoring 2: Setup External Resource

explicitly creates resources

release them when done

Page 42: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Refactoring 3: Make Resource Unique

or

Page 43: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Refactoring (F:110): Extract Method

Page 44: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Refactoring (F:110): Extract Method

Page 45: Refactoring Test Codectchen/pdf/RTC.pdf · Why Refactoring Test Code The ideal test code / production code ratio approaches 1:1, it is not surprising that unit tests are begin refactored

Example- Refactoring 5: Add Assertion Explanation