B-Refactoring: Automatic Test Code Refactoring to Improve Dynamic ...
Refactoring
-
Upload
nkaluva -
Category
Technology
-
view
492 -
download
3
Transcript of Refactoring
Refactoring: A Brief Introduction
Refactoring
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 existing software by applying a series of refactorings without changing its observable behavior.
An Example with NUnit
#region Usingusing NUnit.Framework;#endregion
namespace com.sds.prime{ [TestFixture] public class PrimeTest { [Test] public void testMethod() { Prime prime = new Prime(); } }}
An Example with NUnit
using System;
namespace com.sds.prime{ public class Prime { public Prime() { } }}
Run Test with NUnit plugin
Run Test with NUnit plugin
------ Test started: Assembly: PrimeNumber.exe ------
1 succeeded, 0 failed, 0 skipped, took 0.05 seconds.
---------------------- Done ----------------------
An Example with NUnit
#region Usingusing NUnit.Framework;#endregion
namespace com.sds.prime{ [TestFixture] public class PrimeTest { [Test] public void testMethod() { Prime prime = new Prime(); Assert.IsTrue(prime.getNext(1) == 1); } }}
An Example with NUnit
using System;
namespace com.sds.prime{ public class Prime { public Prime() { }
public int getNext(int a_numberOfPrimes) { return 1; } }}
Run Test with NUnit plugin
Run Test with NUnit plugin
------ Test started: Assembly: PrimeNumber.exe ------
1 succeeded, 0 failed, 0 skipped, took 0.05 seconds.
---------------------- Done ----------------------
An Example with NUnit
#region Usingusing NUnit.Framework;#endregion
namespace com.sds.prime{ [TestFixture] public class PrimeTest { [Test] public void testMethod() { Prime prime = new Prime(); Assert.IsTrue(prime.getNext(1) == 1); Assert.IsTrue(prime.getNext(2) == 2); } }}
An Example with NUnit
using System;
namespace com.sds.prime{ public class Prime { public Prime() { }
public int getNext(int a_numberOfPrimes) { if (a_numberOfPrimes== 1) return 1; if (a_numberOfPrimes == 2) return 2; } }}
Run Test with NUnit plugin
Run Test with NUnit plugin
------ Test started: Assembly: PrimeNumber.exe ------
1 succeeded, 0 failed, 0 skipped, took 0.05 seconds.
---------------------- Done ----------------------
An Example with NUnit
#region Usingusing NUnit.Framework;#endregion
namespace com.sds.prime{ [TestFixture] public class PrimeTest { [Test] public void testMethod() { Prime prime = new Prime(); Assert.IsTrue(prime.getNext(1) == 1); Assert.IsTrue(prime.getNext(2) == 2); Assert.IsTrue(prime.getNext(10) == 23); } }}
An Example with NUnitpublic int getNext(int a_numberOfPrimes){ if (a_numberOfPrimes== 1) return 1; if (a_numberOfPrimes == 2) return 2;
int primeCounter = 2; for (int candidate=3; candidate < 1000; candidate++) { if (isPrime(candidate)) { primeCounter++; if (primeCounter == a_numberOfPrimes) return candidate; } }
return 0;}
An Example with NUnitprivate bool isPrime(int a_potentialPrime){ bool isPrime = true;
for (int potentialDivisor = 2; potentialDivisor < a_potentialPrime; potentialDivisor++) { if (a_potentialPrime % potentialDivisor == 0) { isPrime = false; break; } } return isPrime;}
Run Test with NUnit plugin
Run Test with NUnit plugin
------ Test started: Assembly: PrimeNumber.exe ------
1 succeeded, 0 failed, 0 skipped, took 0.05 seconds.
---------------------- Done ----------------------
An Example with NUnitpublic int getNext(int a_numberOfPrimes){ if (a_numberOfPrimes== 1) return 1; if (a_numberOfPrimes == 2) return 2;
int primeCounter = 2; for (int candidate=3; candidate < 1000; candidate+2) { if (isPrime(candidate)) { primeCounter++; if (primeCounter == a_numberOfPrimes) return candidate; } }
return 0;}
An Example with NUnitprivate bool isPrime(int a_potentialPrime){ bool isPrime = true; int halfWay = a_potentialPrime / 2;
for (int potentialDivisor = 2; potentialDivisor < halfWay; potentialDivisor++) { if (a_potentialPrime % potentialDivisor == 0) { isPrime = false; break; } } return isPrime;}
Run Test with NUnit plugin
Run Test with NUnit plugin
------ Test started: Assembly: PrimeNumber.exe ------
1 succeeded, 0 failed, 0 skipped, took 0.05 seconds.
---------------------- Done ----------------------
Testing Boundary Conditions
As developers, we generally code with the core of the requirement in mind. We test the ‘common’ scenarios and mark it complete. However, most of our code breaks around our boundary conditions.
Refactoring
Now back to Refactoring.
An Example …
Smells
A smell is a warning sign about a potential problem.
Code Smells
Common smells in our code• Comments• Long Methods• Large Class• Long Parameter List• Inappropriate Intimacy• Duplicated Code• Conditional Complexity
A list of descriptions can be found here
http://www.codinghorror.com/blog/archives/000589.html
Smell:Comments
When a comment explains a block of code, use Extract Method to pull the block out into a properly named method.
When a comment explains what a method does, use Rename Method to give the method a more descriptive name.
Payoff: Improves communication, may expose duplication.
Smell:Long Methods
Use Extract Method to break up the method into smaller pieces.
Payoff: Improves communication, may expose duplication, often helps new classes and abstractions emerge.
Smell:Large Class
Use Extract Class if you can identify a new class that has part of this class’s responsibilities.
Use Extract Subclass if you can divide responsibilities between the class and a new subclass.
Use Extract Interface if you can identify subsets of features that clients use.
Payoff: Improves communication, may expose duplication.
Smell:Long Parameter List
If the parameter value can be obtained from another object this
one already knows use Replace Parameter with Method.
If the data is not from one logical object, you may be able to
group them using Introduce Parameter Object.
Payoff: Improves communication, may expose duplication, often reduces size.
Smell:Inappropriate Intimacy
If two independent classes are entangled, use Move Method
and Move Field to put the right pieces in on the right class.
If the tangled part seems to be a missing class, use Extract Class and Hide Delegate to introduce the new class.
Payoff: Reduces duplication, often improves communication, may reduce size.
Design Patterns
Design patterns are used in Object Oriented (OO) programming to create structured, adaptive classes. Refactoring ultimately results in some kind of design pattern.
Template Pattern
MyClass::someMethod() {
aaa aaa aaa aaabb bb bb bb bb cccc cccc cccc d d d d d d d d deee eee eee eee fffff ff fffff ffggg gggg ggg h hh h hh h hh hiiii iiii iiii iiii
}
Design Patterns Explained, ‘Chapter 19 : The Template Method Pattern’, by Alan Shalloway and James R. Trott
Template Pattern
Using copy and paste to create new code from existing code results in redundancies
aaa aaa aaa aaabb bb bb bb bb cccc cccc cccc d d d d d d d d deee eee eee eee fffff ff fffff ffggg gggg ggg h hh h hh h hh hiiii iiii iiii iiii
AAA A AAAA AXXX XX XX XBB BB B cccc cccc cccc DDD D DDD DEE EEEE E E fffff ff fffff ffGGG G G GGGG HHH HHH HH Hiiii iiii iiii iiii
Design Patterns Explained, ‘Chapter 19 : The Template Method Pattern’, by Alan Shalloway and James R. Trott
Template Pattern
MyClass::someMethod() {
methodForStep1()
cccc cccc cccc
methodForStep3()
fffff ff fffff ff
methodForStep5()
iiii iiii iiii iiii }
Design Patterns Explained, ‘Chapter 19 : The Template Method Pattern’, by Alan Shalloway and James R. Trott
methodForStep1() {
aaa aaa aaa aaa
bb bb bb bb bb
}
methodForStep3() {
d d d d d d d d d
eee eee eee eee
}
methodForStep5() {
ggg gggg ggg
h hh h hh h hh h
}
Template Pattern
BaseClass::someMethod() {
methodForStep1()
cccc cccc cccc
methodForStep3()
fffff ff fffff ff
methodForStep5()
iiii iiii iiii iiii }
Design Patterns Explained, ‘Chapter 19 : The Template Method Pattern’, by Alan Shalloway and James R. Trott
MyClass {
methodForStep1() {
aaa aaa aaa aaa
bb bb bb bb bb
}
methodForStep3() {
d d d d d d d d d
eee eee eee eee
}
methodForStep5() {
ggg gggg ggg
h hh h hh h hh h
}
}
MySecondClass {
methodForStep1() {
AAA A AAAA A
XXX XX XX X
BB BB B
}
methodForStep3() {
DDD D DDD D
EE EEEE E E
}
methodForStep5() {
GGG G G GGGG
HHH HHH HH H
}
}
Prime Number Template
We could easily abstract our Prime class using the Template pattern so that we can handle different algorithms of the Prime number generator.
Resources
“Test Patterns Explained” by Alan Shalloway, James R. Trott“Refactoring” by Martin Fowler, www.refactoring.com“Pragmatic Unit Testing in C# with Nunit” by Andrew Hunt, David Thomas“The Pragmatic Programmer” by Andrew Hunt, David Thomas
Code Smells, http://www.codinghorror.com/blog/archives/000589.htmlXunit Frameworks, http://www.opensourcetesting.org/unit_misc.phpTestDriven VS Plugin, http://www.testdriven.net/