Retrofitting Unit Tests - PowerPoint PPT Presentation

1 / 27
About This Presentation
Title:

Retrofitting Unit Tests

Description:

Paul Simmons. XtC. Retrofitting Unit Tests. Motivation. Stroking his chin sagely ... no testing safety net to support 'agility' complete test suite is expensive ... – PowerPoint PPT presentation

Number of Views:48
Avg rating:3.0/5.0
Slides: 28
Provided by: xpday2
Category:

less

Transcript and Presenter's Notes

Title: Retrofitting Unit Tests


1
Retrofitting Unit Tests
  • Steve FreemanXtC, Thomson Financial
  • Paul SimmonsXtC

2
Motivation
  • Stroking his chin sagely the old man replied,
  • Well now, if I was going there I wouldnt be
    starting from here.

3
Retrofitting Unit Tests
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • What is Retrofitting?
  • Box of fears
  • Show me the code
  • Opening the box
  • Retrofitting Revisited

Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
4
Why Unit Tests?
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • Powerful design/specification technique
  • Focus on what matters
  • Executable documentation
  • Support for code maintenance
  • Refactor with (justified) confidence
  • Quality is free
  • Cuts debug time

5
Why retrofit Unit Tests?
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • The Scenario
  • youre working on legacy code
  • i.e. anything without unit tests
  • you need to make changes
  • The Dilemma
  • no testing safety net to support agility
  • complete test suite is expensive takes time
  • code not suitable for testing, anyway

6
Box of Fears
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
7
A Three-Step Approach
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • Some judicious functional testing.
  • To catch gross errors
  • Identify code smells
  • Long methods, Singletons, c, c.
  • Carefully refactor
  • without unit tests!

8
Code Example (i)
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • Smells Singleton, Static Initialiser
  • Refactor Pass singletons through, Replace class
    with interface
  • What does the test look like?
  • Why bother?

9
Singleton
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
cashMachine.withdraw(200) public class
CashMachine private User user
User.getCurrent() public void withdraw(int
amount) accountManager.debit(user.getAccou
ntId(), amount)
  • Cannot substitute User for testing
  • Worse if creation of singleton User is also
    private
  • Often, User is a catch-all class with lots of
    irrelevant detail

10
Refactor pass singleton through
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
cashMachine.withdraw(200, User.getCurrent()) pub
lic class CashMachine //private User user
User.getCurrent() public void withdraw(int
amount, User user) accountManager.debit(us
er.getAccountId(),
amount)
  • Start to pull out global state
  • Still too hard to substitute a User

11
User
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
public class User current // create
singleton public AccountId getAccountId()
static public User getCurrent()
return current
  • No external control over how Users are created
  • Hidden away in static code

12
Refactor introduce interface
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
public interface AccountHolder AccountId
getAccountId() public class User implements
AccountHolder public AccountId getAccountId()
static public User getCurrent()
return current
  • Separate out that part of the object we need
  • Why? Types with clear responsibilities

13
Before use of interface
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
cashMachine.withdraw(200, User.getCurrent()) pub
lic class CashMachine public void
withdraw(int amount, User user)
accountManager.debit(user.getAccountId(),
amount)
  • Start to pull out global state
  • Still too hard to substitute a User

14
Refactor apply interface
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
cashMachine.withdraw(200, User.getCurrent()) pub
lic class CashMachine public void
withdraw(int amount,
AccountHolder accountHolder)
accountManager.debit( accountHolder.getAc
countId(), amount)
  • Code is more focussed
  • Can substitute other implementations

15
enables unit testing
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
public void testWithdrawal() final AccountId
accountId new AccountId() AccountHolder
holderStub new AccountHolder() public
AccountId getAccountId() return
accountId cashMachine.setAccountMana
ger(mockAcctManager) mockAcctManager.setExpecte
dWithdraw( accountId,
200) cashMachine.withdraw(200, holderStub)
mockAcctManager.verify()
1. 2. 3. 4. 5.
16
Why bother (i)?
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • Now we can test the cash machine in isolation
  • Similarly for the accountManager
  • Better modularity means less test setup
  • Testable in isolation
  • No need to refer to external resources
    (databases, files)
  • More focussed code is easier to think about

17
Code Example (ii)
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • Smells bleeding across layers
  • Refactor introduce interface

18
Bleeding across layers
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
public class BillPaymentScreen private
MainScreen main public void payBill(String
payee, Amount amount) Company company
companies.lookupCode(payee)
main.status.setText("Paying " company)
billPayer.pay(company, amount)
main.status.setText(company " paid") ...
main.status.setForeground(Color.Red)
main.status.setText("Could not pay bill")
  • Difficult to test payBill() in isolation
  • Cannot create a BillPaymentScreen without a
    MainScreen
  • Behaviour and GUI feedback all mixed up

19
Refactor introduce interface
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
public class BillPaymentScreen private
StatusPresenter status public void
payBill(String payee, Amount amount)
Company company companies.lookupCode(payee)
status.show("Paying " company)
billPayer.pay(company, amount)
status.show(company " paid") ...
status.warn("Could not pay bill") ...
  • Clarifies BillPaymentScreen dependencies
  • Not really interested in implementation of
    StatusPresenter
  • First step towards breaking out domain model

20
ScreenStatusPresenter
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
public class ScreenStatusPresenter extends
JTextArea implements StatusPresenter public
void show(String message)
setText(message) public void warn(String
message) setForeground(Color.Red)
setText(message)
  • Have MainScreen implement StatusPresenter itself
  • Or, replace basic text area field in MainScreen
  • New methods describe intention, not just
    implementation

21
...enables unit testing
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
MockStatusPresenter mockStatus new
MockStatusPresenter() BillPaymentScreen
paymentScreen new BillPaymentScreen(mockStat
us) public void testPayBill()
mockStatus.addExpectedShow("Paying Tuesday
Club") mockStatus.addExpectedShow("Tuesday
Club paid") mockBillPayer.expectPay(tuesdayClub
, 150) paymentScreen.payBill("xtc", 150)
mockBillPayer.verify() mockStatus.verify()
22
MainScreen
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
public class MainScreen private
ScreenStatusPresenter status private
BillPaymentScreen billPayment ... private
void setupDisplay() status new
ScreenStatusPresenter() billPayment new
BillPaymentScreen(status) addComponent(billPa
yment) addComponent(status) ...
  • Start introducing structure to MainScreen
  • Clarify status presentation for whole
    application

23
Why bother (ii)?
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • Now we can unit test the BillPaymentScreen
  • Don't have to create the whole GUI
  • Begun to clarify model vs. View
  • StatusPresenter becomes a model listener
  • Introducing modularity into the GUI
  • Isolating all the status handling
  • Do the same for other features

24
Code Smells
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • Code Smells
  • Singleton
  • Complex construction
  • Static Initialization
  • Bleeding across layers
  • Classes as parameters
  • Data class
  • Imprecise exceptions
  • Long method
  • Refactorings
  • Pass singletons through
  • Separate construction from use
  • Remove static initializers
  • Weaken dependancies between layers
  • Replace class with interface

25
Open the Box of Fears
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
26
Retrofitting Revisited
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
  • Retrofitting unit tests is painful and expensive,
    but necessary
  • What really matters is attitude
  • and someone to watch your back
  • You can chip away at your code base
  • Build up a test suite incrementally
  • Sometimes its better to rewrite
  • On the small scale

27
Retrofitting Unit Tests
Retrofitting?
Box of Fears
Code Examples
Open the Box
Revisited
If you do not start adding unit tests today
then one year from now you will still not have a
good unit test suite. Don Wells
Write a Comment
User Comments (0)
About PowerShow.com