This document discusses refactoring test code to improve its design and maintainability without changing its behavior. It defines test code elements like test methods, classes, and suites. It presents refactorings for each element like decomposing assertions, joining similar tests, and mirroring the production code hierarchy. It explains why test smells emerge and how automating refactorings and behavior verification could help future test code refactoring. The goal is to evolve test code design along with production code design while keeping tests easy to maintain and their behavior intact.
3. Source code is simple to
understand and can
address only the current
requirements.
It is easier to maintain and
evolve a simple and
organized code structure.
5. To add or change
functionality you need to
deal with existing tests!
6. “.. keep it (tests) at good object-
oriented design, so than if we need
to make a change or add something
or kick something away , we only
have to do that in may be one place
and not in two hundred different
scripts.“
Lisa Crispin
Author of “Agile Testing“
Software Engineering Radio Podcast
7. How can I
How can I
verify
define what is
maintainance
the test code
of test code
behavior?
behavior?
9. Test Target → instance used
A in the test.
Action → changes environment
or the Test Target.
Assertion → comparison
between the Test Target behavior
and the expected one.
10. Test → a sequence
of at least one action
and one assertion.
A A
11. A A
A A
A A A
Test Suite → a set of tests that
can be independently executed.
18. Test Method
Refactorings
Changes actions and
assertions for
equivalent ones.
19. Test Method
Refactorings
● Add Assertion Explanation
● Introduce Assertion Method
● Simplify Test Scenario
● Separate Action from Assertion
● Decompose Assertion
20. Decompose
Assertion
@Test @Test
public void needyEmployee{ public void needyEmployee{
Employee e = new Employee(); Employee e = new Employee();
e.setPayment(300); e.setPayment(300);
assertTrue(“Employee Profile”, assertTrue(“Needy employee”,
e.isNeedy() && e.isNeedy());
e.getDiscount() == 0); assertEquals(“Employee is free”,
} e.getDiscount(), 0);
}
21. Test Class
Refactorings
Reorganize actions
and assertions
among methods in
the same test class.
22. Test Class
Refactorings
● Add Fixture
● Introduce Initialization Method
● Inline Initialization Method
● Join Incremental Tests
● Split Test
● Join Similar Tests with
Distinct Data
40. The test is now covering one
possible composition of
ScheduledExecution, but it can be
composed by any Executor subclass!
Split Tests
From
Composition
46. Verify Test Behavior
Maintainance with Mutants
Create a tool that executes
tests on test target
mutants before and after
the refactoring to verify if
the test behavior was
changed.
47. “Unlike production code, which you
don't have a choice but to maintain,
tests are optional, you can always
stop running them and just throw
them away, and any investment
that you made (...) are just throw
out the window.“
Gerard Meszaros
Author of “xUnit Test Patterns“
Software Engineering Radio Podcast