Methodology - PowerPoint PPT Presentation

1 / 162
About This Presentation
Title:

Methodology

Description:

Fake object. Sandboxing. Transaction rollback. Stored procedures test. Table truncation teardown ... http://wiki/doku.php?id=r_d:cruisecontrol. MS Unit Tests ... – PowerPoint PPT presentation

Number of Views:102
Avg rating:3.0/5.0
Slides: 163
Provided by: pgG5
Category:
Tags: fake | id | methodology

less

Transcript and Presenter's Notes

Title: Methodology


1
Methodology
  • Rigid approaches
  • Prince2
  • RUP
  • Agile development
  • XP
  • Test Driven Development
  • Design Driven Development

2
XP
  • Feedback
  • Assuming simplicity
  • Incremental changes (instead embracing change)
  • Continois integratgion
  • Incremantal development (short period)
  • Refactoring
  • Unit tests
  • Code over documentation
  • Pair programming

3
Unit test example (NUnit)
4
VSTS Overview members (1)
5
VSTS code coverage
6
Unit testing framework
  • Microsoft unit framework VS2005 Team Edition or
    VS2008
  • integrated with VS (debugging etc.)
  • generating Tests from Existing Code
  • generating accessors for Private Methods,
    Properties, and Fields
  • code coverrage
  • NUnit or mbUnit
  • Widely used by the community
  • Several plugins for integration of NUnit or
    mbUnit with VS are available

7
N/MBUnit supporting tools
  • Code coverage NCover, NCoverExplorer
  • Analyze unit test runs to find out which parts of
    application code have been tested
  • Generate coverage reports and statistics
  • Integration
  • Test Mattrix (commercial)
  • TestDriven.Net (commercial)
  • ReSharper (commercial)
  • NUnitGen

8
Some tools
  • Static Analysis FXCop, Vil
  • FXCop is also in VSTS, Vil provides advanced code
    metrics
  • Mock framework
  • RhinoMock or TypeMock

9
Test inputs and outputs
  • Direct input
  • Inputs and calls to components programmed in unit
    test
  • Direct output
  • All results of programmed actions in unit test
    that are directly controllable withing the test
    program (ie. in form of variables)
  • Indirect input
  • Dependencies of CUT that can influence test
    results, ie. events
  • Indirect output
  • Results of actions programmed into testing code
    that are external to unit test, ie. data saved to
    a file

10
Unit testing typical scenarios
  • Standard unit tests
  • Provides references to libraries with code to be
    tested
  • Write test fixtures testing code
  • Provide assertions and expected values
  • Plug tests into the overnight
  • Database unit tests
  • Write set-up and tear-down constructs for
    initializing databases under test
  • Control db state with use of transactions
  • Provide assertions and expected values
  • Plug tests into the overnight
  • WinForms / Web tests
  • Record tests by clicking on forms
  • Provide assertions and expected values
  • Plug tests into the overnight

11
Test stubs How to test before jobs done
  • To turn off DOCs we use different kind of stubs,
    depending on the stituation
  • Basic stub types
  • Responder
  • Write DOCs routines with hardcoded return
    statements with correct values
  • Saboteur
  • Write DOCs routines with hardcoded throw
    exceptions statements or returning incorrect
    values
  • Stubbing techniques
  • Hand-coded (classic)
  • Dynamically generated (mock)

12
Test stub example CUT (1) Main class
  • namespace Stubs
  • public class DbAccessImpl IDbAccess
  • public double getUserAccountStatus (strin
    g user, string password, IVerify verifier)
  • if (verifier.verifyUser(user,
    password))
  • if (user.Equals("user1"))
  • return 100.30
  • else if (user.Equals("user2"))
  • return 10.10
  • else
  • throw new UserAccountExceptio
    n("User not found")

13
Test stub example (2) CUTInterfaces and DOCs
  • public interface IDbAccess
  • double getUserAccountStatus(string user,
    string password, IVerify verifier)
  • public interface IVerify
  • bool verifyUser(string user, string
    password)
  • namespace Stubs
  • public class VerifierImpl IVerify
  • public bool verifyUser(string user, string
    password)
  • throw new Exception("The methodor
    operation is not implemented.")

14
Test stub example - approaches
  • We are missing real implementation of IVerify
    interface.
  • To be able to test CUT, we need to somehow
    provide replacement for IVerify implementation
  • There are four basic approaches
  • Create test for real implementation and leave it
    failing
  • Create a responder
  • Create a saboteur
  • Create a mock

15
Test stub example failing test
  • Test
  • public void DbAccessImplTest()
  • string user "user1"
  • string password "correctpassword"
  • double expected 100.30
  • IDbAccess idb new DbAccessImpl()
  • IVerify verifier new
    VerifierImpl()
  • double actual idb.getUserAccountSt
    atus(user, password, verifier)
  • Assert.AreEqual(expected, actual, "It
    won't work")

16
Test stub example - responder
  • class VerifierResponder IVerify
  • public bool verifyUser(string user, string
    password)
  • return true
  • Test
  • public void DbAccessResponder()
  • string user "user1"
  • string password "correctpassword"
  • double expected 100.30
  • IDbAccess idb new DbAccessImpl()
  • IVerify verifier new
    VerifierResponder()
  • double actual idb.getUserAccountStat
    us(user, password, verifier)

17
Test stub example saboteur (1)How does our app
behave in special conditions
  • class IDbAccessSabouteur1 IVerify
  • public bool verifyUser(string user,
    string password)
  • return false
  • Test
  • ExpectedException DbConnectionException
  • public void DbAccessSaboteur()
  • string user "user1"
  • string password "correctpassword"
  • double expected 100.30
  • IDbAccess idb new DbAccessImpl()
  • IVerify verifier new
    IDbAccessSabouteur1()

18
Test stub example saboteur (2)Are we catching
our exceptions?
class IDbAccessSabouteur2 IVerify
public bool
verifyUser(string user, string password)
throw new DbAccessException()
Test ExpectedException
DbConnectionException public void
DbAccessSaboteur() string
user "user1" string password
"correctpassword" double expected
100.30 IDbAccess idb new
DbAccessImpl() IVerify verifier
new IDbAccessSabouteur2() double
actual idb.getUserAccountStatus(user,
password, verifier)
Assert.AreEqual(expected, actual, will it
work?")
19
Test stub example - mock
SetUp public void setup() mocks new
Mockery()
  • Test
  • public void DbAccessMock()
  • string user "user1"
  • string password "correctpassword"
  • double expected 100.30
  • IVerify aMock (IVerify)mocks.NewMock
    (typeof(IVerify))
  • Stub.On(aMock).Method("verifyUser")
  • .With( new Object user,
    password )
  • .Will(Return.Value( true ))
  • IDbAccess idb new DbAccessImpl()
  • double actual idb.getUserAccountStat
    us(user, password, aMock)
  • Assert.AreEqual(100.30, actual, "It
    works! ")

20
Database testing
  • A bit harder than standard code-only unit test
  • There exists several approaches on how to test
    code that depends on database layer and the
    database layer itself
  • Fake object
  • Sandboxing
  • Transaction rollback
  • Stored procedures test
  • Table truncation teardown

21
GUI testing
  • Logic spagetti Events/cod/business logic
  • How to test state of application
  • Framereworks

22
  • NUnit presentation

23
Unit test example (NUnit)
24
NUnit Assertions (1)
  • Assertions - classic model
  • Standard Assert
  • Assertion.Assert ( boolean condition)
  • Equality
  • Assert.AreEqual( object expected, object actual,
    string message, params object parms )
    AssertNotEqual (...)
  • Identity
  • Assert.AreSame( object expected, object actual,
    ... )
  • Assert.Contains( object anObject, IList
    collection, ... )
  • ... and similar
  • Comparison
  • Assert.Greater( IComparable arg1, IComparable
    arg2, ... )
  • ... and similar

25
NUnit Assertions (2)
  • Type
  • Assert.IsInstanceOfType ( Type expected, object
    actual, ... )
  • Assert.IsAssignableFrom
  • ... and similar
  • Condition
  • Assert.IsTrue( bool condition, ... )
  • Assert.IsNull( object anObject, ... )
  • Assert.IsNaN( double aDouble, ... )
  • Assert.IsEmpty( ICollection collection, ... )
  • ... and similar
  • Utility
  • Assert.Fail( ... )
  • Assert.Ignore( ... )

26
NUnit Assertions (3)
  • String
  • StringAssert.Contains (string expected, string
    actual, ... )
  • StringAssert.StartsWith( ...)
  • ... and similar
  • Collections
  • CollectionAssert.AllItemsAreInstancesOfType
    (Collection collection, Type expectedType )
  • CollectionAssert.AllItemsAreNotNull
  • CollectionAssert.AreEqual
  • CollectionAssert.AreEquivalent
  • CollectionAssert.IsSubsetOf
  • ... and similar
  • File
  • FileAssert.AreEqual( Stream expected, Stream
    actual )
  • ... and similar

27
NUnit Assertions (4)
  • Assertions - constraint model
  • Assert.That ( object actual, IConstraint
    constraint, string message, object parms )
  • public interface IConstraint bool Matches(
    object actual ) void WriteMessageTo(
    MessageWriter writer ) void
    WriteDescriptionTo( MessageWriter writer )
    void WriteActualValueTo( MessageWriter writer )

28
NUnit - Attributes
  • Basic
  • Test
  • TestFixture
  • Setup
  • Teardown
  • Others
  • Category
  • Description
  • Expected Exception
  • Explicit
  • Ignore
  • Platform
  • Property
  • SetUpFixture
  • Suite
  • TestFixtureSetUp
  • TestFixtureTearDown

29
  • MSTESTS presentation

30
MS Unit Tests and NUnit
31
MS Unit Tests and NUnit
32
MS Unit Tests and NUnit
  • Frameworks have a lot in common. Sometimes the
    name
  • are even the same.
  • MS Unit Test is enriched by fallowing features
  • DataSource possibility of driven unit tests by
    data stored in database.
  • TestProperty additional information about test
    case passed to report generated by test runner.
  • Assertion available as generics. Checking type of
    parameters in compilation time.
  • Assertions in MS Unit Test are stronger. They
    required type equality i.e. Assertion( (int)1 ,
    1L ) will file.
  • More information http//wiki/doku.php?idr_dcrui
    secontrol

33
MS Unit Tests Attributes
  • TestMethod mark a method as a test method.
  • TestClass mark a class as a test class.
  • AssemblyInitialize and AssemblyCleanup mark
    methods that execute before and after all of the
    tests in an assembly are executed.
  • ClassInitialize and ClassCleanup mark
    methods that execute before and after all of the
    tests in a class are executed.
  • TestInitialize and TestCleanup mark methods
    that execute before and after each test method is
    executed
  • DeploymentItem - used to specify deployment
    items such as files or directories for per-test
    deployment.
  • DataSource - provides data source-specific
    information for data-driven testing

34
Attributes that provide additional inftormation
about test methods.
  • These attributes are useful when you are working
    with
  • hundreds of unit tests and you need to manage the
    tests by
  • sorting and filtering the tests
  • Owner Enables you to specify the author of a
    test method
  • Description Enables you to provide a
    description of a test method
  • Priority Enables you to specify an integer
    priority for a test
  • TestProperty Enables you to specify an
    arbitrary test property

35
Data Driven Tests
  • A data-driven unit test is a unit test that is
    run repeatedly for each row in a data source.
  • When a data-driven unit test is running, data is
    retrieved from the rows of a data source. The
    data is available to the running unit test
    through the DataRow and DataConnection properties
    of the TestContext class.
  • TestContext.DataRow"LastName"

36
Data Driven Tests
  • namespace TestProject1
  • TestClass
  • public class TestClass
  • private TestContext m_testContext
  • public TestContext TestContext
  • get return m_testContext
  • set m_testContext value
  • TestMethod
  • DeploymentItem("FPNWIND.MDB")
  • DataSource("System.Data.OleDb",
    "ProviderMicrosoft.Jet.OLEDB.4.0
  • DataSource\"FPNWIND.MDB\"",
    "Employees", DataAccessMethod.Sequential)
  • public void TestMethod()
  • Console.WriteLine( "EmployeeID 0,
    LastName 1",
  • TestContext.DataRow"EmployeeID",
    TestContext.DataRow"LastName" )

37
UT in practice
38
UnitTests
  • Isolation
  • Speed
  • Self containment
  • Race safe
  • Independence
  • Well documented
  • Maintainable

39
Some Patterns
  • Simple test
  • Exception
  • Testing protected methods/properties, overriding
    methods
  • Reflection usage
  • Mock usage

40
Pattern 1 4 Stage Testing
  • When to use
  • This is the normal testing scheme.
  • How to use
  • TestFixture per tested class
  • Setup prerequisite Objects - Create the scenario
    of the test, this can be done in the test method
    or in the SetUp and TestFixtureSetUp methods
  • Call the method being tested
  • Valuate the results
  • Teardown the Objects

41
Very simple class
  • public class Authentication
  •  private string _key public string Key   
      get  return _key     set _key
    value  public string EncodePassword(string
    password)      // do the encoding    return
    encoded_password 


42
... and very simple test
  • TestFixture
  • public class TestFixture1
  •    Authentication authenticator  String
    name  SetUp public void Init()        // se
    t up our authenticator and key     authenticator
    new Authentication()     authenticator.Key
    "TESTKEY"     name "user"  
  • ...

43
... and very simple test
  • TearDown public void End()
  •  // finish tests authenticator.Key ""
  • Test public void Encoding ()
  •  // continue specific test set up  String
    expectedKey "fwe94t-gft5" // Call our
    method String recivedKey authenticator.Enco
    dePassword(name) // Validate that for "user"
    and "TESTKEY"
  • //key we should get our key Assert.AreEqual(exp
    ectedKey,recivedKey)

44
Pattern 2 Test Exception
  • When to use
  • When we are expect our test to raise an
    exception
  • How to use
  • Use nUnit's ExpectedException attribute

45
Exceptions are not exceptional
  • public string EncodePassword(string password)
  • if (passwordnull password.Length0)
       throw new ValidationException ("Passwor
    d is empty")  
  • // do the encodingreturn encoded_password

46
Exceptions are not exceptional
  • Test
  • ExpectedException(ValidationException, "Pass
    word is empty")
  • public void Encoding ()
  • authenticator.EncodePassword(null)

47
Pattern 3 Inner Class
  • When to use
  • When a protected entity (field or method), needs
    to be accessed for the test. We need to
  • test a protected method or access a protected
    field.
  • override a public or protected (virtual) method
  • How to use
  • Create a new class that extends our tested class
  • To test a protected method, add a method in our
    extended class that calls the protected method
    (Delegation).
  • To override a method, override this method in our
    extended class. 

48
protected string EncodePassword
  • class TestAuthentication Authentication
  •  public string CallEncodePassword(string
    password)       // We can call a protected
    method from here      return EncodePassword(passw
    ord) 
  • Test public void Encoding ()
  • TestAuthentication authenticator
  • new TestAuthentication()authenticator.Key
      "TESTKEY"String expectedKey
    "fwe94t_at_5"String name "user"// call the
    tested method by means of the Inner Class
  • Assert.AreEqual(expectedKey,authenticator.
  • CallEncodePassword(name))

49
override virtual int DoSelect
  • override a public or protected (virtual) method
  • public bool IsAuthenticated(string name,string
    password)
  • // do somethingint Results
    DoSelect(statement)return Results1
  • protected virtual int DoSelect(string statement)
  • // do something

50
  • Test public void Authenticated ()
  • TestAuthentication authenticator new
    TestAuthentication() // if 1 record found
    should be authenticated authenticator.returnAmoun
    t 1 Assert.IsTrue(authenticator.
    IsAuthenticated("user","password"))
  •    
  • // if no records found should not // be
    authenticated authenticator.returnAmount
    0 Assert.IsFalse(authenticator. IsAuthenticate
    d("user","password"))

51
Patern 4 Reflection Test
  • When to use
  • When we need to test private methods use the
    reflection test pattern.
  • In most cases we don't need to test private
    methods.
  • How to use
  • Use reflection.
  •  

52
Reflection
  • Test
  • public void Internals ()
  • Type type typeof (Authentication)Authenticat
    ion authenticator (Authentication)type.
  • GetConstructor(System.Type.EmptyTypes).
  • Invoke(null)
  • bool field (bool)type.GetField("privateField,
    BindingFlags.NonPublic BindingFlags.Instance
    BindingFlags.Public) . GetValue(authenticator)A
    ssert.IsTrue(field)bool result
    (bool)type.GetMethod("PrivateMethod,..).
  • Invoke(authenticator ,null)Assert.IsTrue(re
    sult)

53
Pattern 5 Mock usage
  • When to use
  • The real object has non deterministic behavior
    (it produces unpredictable results, like a date
    or the current weather temperature.)
  • The real object is difficult to set up.
  • The real object has behavior that is hard to
    trigger (for example, a network error).
  • The real object is slow.
  • The real object has (or is) a user interface.
  • The test needs to ask the real object about how
    it was used (for example, a test might need to
    confirm that a callback function was actually
    called).
  • The real object does not yet exist (a common
    problem when interfacing with other teams or new
    hardware systems).

54
Pattern 5 Mock usage
  • How to use
  • The three key steps to using mock objects for
    testing are
  • Use an Interface to describe the object
  • Implement the interface for production code
  • Implement the interface in a mock object for
    testing

55
Mocks
MockInit Test Test MockValid
Mocked ...
CUT
56
  • IList subscriberpublic void AddSubscriber(ISubs
    criber subscriber)      this.subscriber.Add(sub
    scriber)public bool IsAuthenticated(string
    name, string password)    foreach
    (ISubscriber sub in subscriber)           
    sub.Recive(name)        // do something   
    int Results DoSelect(statment)    return
    Results1
  • public interface ISubscriber     void
    Receive(String message) 

57
NMock
  • Test
  • public void Subscriber()
  •  DynamicMock subscriber new
    DynamicMock(typeof(ISubscriber)) Authentication
    authenticator new Authentication() auth
    enticator.Add( (ISubscriber)
    subscriber.MockInstance)
  •    // expectations subscriber.Expect("Receive",
    new Object "user") //
    execute Assert.IsTrue(authenticator.
    IsAuthenticated("user","password"))
  • subscriber.Verify()
  •  

58
Mocks which one ?
  • NMock
  • TypeMock
  • RhinoMock
  • dynamic/natural syntax ?
  • what can be mocked ?

59
Syntax
  • dynamic
  • mock.Expected(method,parameters,...)
  • NMock2, TypeMock
  • natural
  • mock.method(parameters,...)
  • TypeMock, RhinoMock

60
What can be mocked
  • NMock Interface
  • RhinoMock interface/class (not sealed, only
    virtual methods)
  • TypeMock
  • all above
  • static/non static methods of any class and
    objects, creation of objects as well

61
Design for testability
62
Book
  • Agile Principles Patterns Practices in C -
    Prentice Hall.chm

63
Design Smells
  • Rigidity
  • Fragility
  • Immobility
  • Viscosity
  • Needless complexity
  • Needless repetition
  • Opacity

64
Reasons
  • accumulation of small departures
  • drifting of the requirements ?
  • hurry-up!
  • fragile design ...

65
Blessed Simplicity
  • copy
  • signs
  • from keyboard
  • to printer
  • public class Copier
  • public static void Copy()
  • int c
  • while((cKeyboard.Read()) ! -1)
  • Printer.Write(c)

66
Requirements changes ...
  • from keyboard or tape Reader
  • public class Copier
  • public static bool rdFlag false
  • public static void Copy()
  • int c
  • while((c (rdFlag ? PaperTape.Read()
  • Keyboard.Read()) ! -1)
  • Printer.Write(c)

67
Requirements changes ...
  • to printer or tape punch
  • public class Copier
  • public static bool rdFlag false
  • public static bool ptFlag false
  • public static void Copy()
  • int c
  • while((c (rdFlag ? PaperTape.Read()
  • Keyboard.Read()) ! -1)
  • if (ptFlag) PaperTape.Write(c) else
    Printer.Write(c)

68
Requirements changes ...
  • More sources and more destinations
  • Handle I/O errors
  • Copy and encode characters
  • Log the contents to the file
  • Change the format basing on context (upper first
    letter of the sentence

69
Requirements changes ...
  • always
  • or at least sometimes

70
... be ready
  • public class KeyboardReader
  • public int Read() return Keyboard.Read()
  • public class PrinterWriter
  • public Write(int c) return Printer.Write(c)
  • public class Copier
  • public static KeyboardReader reader new
    KeyboardReader()
  • public static PrinterWriter writer new
    PrinterWriter()
  • public static void Copy()
  • int c
  • while((c(reader.Read())) ! -1)
  • writer.Write(c)

71
Changes in printer, keyboard
  • Changes in printer, keyboard
  • forces changes in copier
  • forces recompilation of copier
  • Copier developer has to know the classes
    PrinterWriter, KeyboardReader
  • Many writer classes have to derive from printer

72
Interface
  • like a class but without
  • implementation
  • attributes
  • private members
  • Interface is designed to be a base
  • can be used as a type of variable (when we plan
    to use instances of implementing classes)
  • cannot be instantiated

73
... for interface
  • public interface Reader
  • public int Read()
  • public class KeyboardReader Reader
  • public int Read() return Keyboard.Read()
  • public class Copier
  • public static Reader reader new
    KeyboardReader()
  • public static Writer writer new
    PrinterWriter()
  • public static void Copy()
  • int c
  • while((c(reader.Read())) ! -1)
  • writer.Write(c)

74
Enigmatic Principles
  • The Single-Responsibility
  • Open/Close
  • Liskov Substitution
  • Dependency-Inversion
  • Interface Segregation

75
Single-Responsibility
  • A class should have only one reason to change.
  • Printers are responsible for writing
  • Readers are responsible for reading

76
Open/Close
  • Software entities (classes, modules, functions,
    etc.) should be open for extension but closed for
    modification
  • new readers/writers/formatters might be added in
    easy way

77
STRATEGY Pattern
78
TEMPLATE METHOD pattern
79
Liskov Substitution
  • Subtypes must be substitutable for their base
    types.
  • TapeReader KeyboardReader ???
  • Derive means is a kind of
  • Agreggation is usually better than deriving
  • Deriving interfaces over deriving implementation

80
Dependency-Inversion
  • High-level modules should not depend on
    low-level modules. Both should depend on
    abstractions.
  • Abstractions should not depend upon details.
    Details should depend upon abstractions.
  • Should copier deppend on reader
  • Should reader depend on copier?
  • ... both should depend on interfaces

81
The interface segregation
  • Clients should not be forced to depend on
    methods they do not use.
  • Reader interface should be separate from writer
    interface
  • Interface is more clear than a class
  • Interfaces should be consistent
  • Interfaces should not be to wide (WCF optimal
    3-5-9)

82
Interface should be (introduced)
  • when
  • there will be subclasses
  • when the class will be exposed (modules, users,
    services...)
  • optionally for compound parameters
  • - public properties (private fields will be
    defined in classes/structures)

83
Some thoughts about UT?
84
Potential problems
  • Wide range of logic covered by single test
  • Long test body
  • Test bases on many aspects of CUT behavior
  • The above implies
  • Potentially frequent changes of test in the
    future
  • Poor problem localization (debugging necessity)
  • Complex of testing code
  • Test cancer possibility

85
Some observations
  • Separating aspects into separate functions
    reduces code necessary to initialize the unit
    test and cause the test code smaller less
    complicated
  • Short code gt short Test but on the other hand,
    is necessary to test the one-line function ?
  • Two forms of returning of value are possible when
  • MYTYPE function()
  • void function(out MYTYPE value)
  • 1st form is more natural, the result can be
    easier set up for this version (by SetResult.For
    )
  • Rhino mock requires- Interfaces- classes
    virtual functions
  • Protected functions can be called via test
    specific subclass or via reflection but private
    only via reflection

86
Good practices
  • Meaningful names of tests
  • One aspect per test.
  • .. so we should avoid the multiplication of
    assertions in a single test (Expect.Call is also
    an assertion)
  • Test shouldnt contain the conditional logic,
    loop etc. (how to test the test ?)
  • The logic of tested code shouldnt be changed for
    purpose of UT introduction (esp. hacks)
  • Dynamic mocks over static mocks
  • SetResult.For over ExpectCall
  • Repeat.Times, VerifyAll, Ordered are not always
    necessary

87
Unit testing flavours
  • State verification, Behavior verification
  • Test after, test first (TDD, BDD)
  • Test After
  • After ? The Day, the Week After,
  • After immediately after
  • Always Fail the test
  • Test Driven Design
  • Suite of tests is a nice side effect of the
    process of DESIGNING application through unit
    tests.

88
Lets imagine TDD?
89
What we know ?
UpdateDictionaries()
listOfDictsToSync foreach (LDTS timestamp
in listOfDictsToSync)
GetOutOfSyncTimestamps
SynchronizeDictionaryForTimestamp
90
  • //public class When_dictionaries_are_being_updated
  • Test
  • public void List_of_out_of_sync_timestamps_is_to_b
    e_retrieved()
  • LDTS listToReturn New.TimestampList(new
    object 1, 2, 3, 4, 5, 6 )
  • SetupResult.For(outOfSynctimestampsProvider.G
    etOutOfSyncTimestamps()). Return(listToReturn)
  • mocks.ReplayAll()
  • sut.UpdateDictionaries()
  • Assert.That(sut.ListOfDictsToSync,
    Is.EqualTo(listToReturn))
  • Test
  • public void Synchronizer_must_be_called_for_each_e
    lement_on_list()
  • LDTS listToReturn New.TimestampList(new
    object 1, 2)SetupResult.For(outOfSynctimest
    ampsProvider.GetOutOfSyncTimestamps()). Return(li
    stToReturn)
  • Expect.Call(synchronizer.SynchronizeDictionaryFor
    Timestamp(listToReturn0))
  • Expect.Call(synchronizer.SynchronizeDictionaryFor
    Timestamp(listToReturn1))
  • mocks.ReplayAll()

91
More decisions ?
UpdateDictionaries()
listOfDictsToSync foreach (LDTS timestamp
in listOfDictsToSync)
GetOutOfSyncTimestamps
GetDictionaryValues
SynchronizeDictionaryForTimestamp
SetDictionary
92
  • //public class When_dictionary_is_synchronized_for
    _given_timestamp
  • Test
  • public void source_dictionary_provider_must_be_ca
    lled_for_values_of\
  • _dictionary_with_given_id_and_timestamp()
  • DictionaryTimestamp timestamp New.Timestamp
  • .WithId(123)
  • .WithTimestamp(DateTime.Parse("08
    2495843"))
  • DateTime actualTimestamp
  • ListltListltstringgtgt contents
  • Expect.Call( sourceDictionaryProvider.GetDiction
    aryValues(timestamp.DictionaryId,
    timestamp.Timestamp, out contents, out
    actualTimestamp))
  • mocks.ReplayAll()
  • sut.SynchronizeDictionaryForTimestamp(timestamp)
  • mocks.VerifyAll()

93
  • //public class When_dictionary_is_synchronized_for
    _given_timestamp
  • Test
  • public void destination_dictionary_with_given_id_m
    ust_be_updated_with_values\
  • _from_source_dictionary()
  • DictionaryTimestamp timestamp New.Timestamp
  • .WithId(123)
  • .WithTimestamp(DateTime.Parse("082495843"))
  • DateTime actualTimestamp
  • ListltListltstringgtgt contents New.Contents
    //initialize
  • Expect.Call( destinationDictionaryUpdater.SetDic
    tionary(timestamp.DictionaryId,
    timestamp.Timestamp,contents))
  • mocks.ReplayAll()
  • sut.SynchronizeDictionaryForTimestamp(timestamp)
  • mocks.VerifyAll()

94
  • public class Library
  • private readonly IOutOfSyncTimestampsProvi
    der outOfSyncTimestampsProvider
  • private readonly IDictSynchronizer
    synchronizer
  • protected IListltDictTimestampgt
    listOfDictstionariesToSync
  • public Library(IOutOfSyncTimestampsProvider
    outOfSyncTimestampsProvider,
    IDictSynchronizer synchronizer)
  • this.outOfSyncTimestampsProvider
    outOfSyncTimestampsProvider
  • this.synchronizer synchronizer
  • public void UpdateDictionaries()
  • listOfDictsToSync outOfSyncTimestamps
    Provider.GetOutOfSyncTimestamps()
  • foreach (LDTS timestamp in
    listOfDictsToSync)
  • synchronizer.SynchronizeDictionary
    ForTimestamp(timestamp)

95
  • TestFixture
  • Category("LibrarySpec")
  • public class When_dictionaries_are_being_updated
  • private MockRepository mocks
  • private IOutOfSyncTimestampsProvider
    outOfSynctimestampsProvider
  • private TestSpecificLibrarySubclass sut
  • private IDictionariesSynchronizer synchronizer
  • SetUp
  • public void SetUp()
  • mocks new MockRepository()
  • outOfSynctimestampsProvider
    mocks.DynamicMockltIOutOfSyncTimestampsProvidergt
    ()
  • synchronizer mocks.DynamicMockltIDic
    tionariesSynchronizergt()
  • sut new TestSpecificLibrarySubclass
    (outOfSynctimestampsProvider,

  • synchronizer)
  • public class TestSpecificLibrarySubclass
    Library

96
  • TestFixture
  • Category("LibrarySpec")
  • public class When_dictionary_is_synchronized_for_g
    iven_timestamp
  • private IDictionariesSynchronizer sut
  • private IDictionariesProvider sourceDictionaryPro
    vider
  • private IDictionariesUpdater destinationDictionar
    yUpdater
  • private MockRepository mocks
  • SetUp
  • public void SetUp()
  • mocks new MockRepository()
  • sourceDictionaryProvider
    mocks.DynamicMockltIDictionariesProvidergt()
  • destinationDictionaryUpdater
    mocks.DynamicMockltIDictionariesUpdatergt()
  • sut new DictionariesSynchronizerImp
    l(sourceDictionaryProvider, destinationDictio
    naryUpdater)

97
Code is important!
  • Developer can sometimes get away with bad design
    when there are no unit tests - just more time
    will be spent on development and more bugs tester
    will have to find. When unit tests are there bad
    design end up in brittle unit tests that are to
    big, test multiple responsibilities and break
    much too often - then there are two options - fix
    the design and unit tests or dump unit testing
    altogether and carry on with bad design.
  • So - Do not write poor tests!
  • Most important thing in unit testing is good OO
    design.
  • Single responsibility principle
  • Open Close principle
  • Liskovs Substitution principle
  • Interface segregation principle
  • Dependency inversion principle
  • RoleInterfaces vs wide interfaces (seggregation)

98
A bit more toughts
  • There are more to test doubles than just mocks!
    Use test specific subclasses, fakes and stubs
    (you can create some of those in Rhino Mocks)
  • AutoMockingContainer Rhino Mocks Windsor IoC
    container
  • Mocks all dependencies automatically with dynamic
    mocks
  • Tests less coupled to implementation
  • One doesn't care about dependencies irrelevant to
    current test
  • Tests might become less understandable -
    something happens under the hood
  • Problematic when constructor contains logic under
    test - we need to setup mocks and expectations
    before AutoMockingContainer kicks in

99
So... how to start?
  • What may be the steps?
  • Write tests for simple fuctions with some logic
    (conditional, loops)
  • Short, clear and simple unit tests code (no
    logic in the test, no hacks in the code, no
    REPETITIONS)
  • Single logical assertion
  • Meaningful names
  • Proper ussage of Mocks
  • Write tests for functions when a simple
    extraction of logic is possible
  • Try to refactor the code (with some UT already
    written)
  • Try to write the tests correctly for the new code
    i.e.
  • test before or immediatelly after

100
Refactoring ?
101
Contents
  • First rendezvous
  • TDD and continues refactoring
  • Why should you refactor?
  • When should you refactor?
  • Strategy
  • Bad smells in code
  • Low level refactoring technics
  • Refactoring to design patterns

102
First rendezvous
  • Refactoring a change made to the internal
    structure of software to make it easier to
    understand and cheaper to modify without changing
    its observable behavior.

103
A bit of propaganda
  • Programs that are hard to read are hard to
    modify.
  • Programs that have duplicated logic are hard to
    modify.
  • Programs that require additional behavior that
    requires you to change running code are hard to
    modify.
  • Programs with complex conditional logic are hard
    to modify.
  • Any fool can write code that a computer can
    understand. Good programmers write code that
    humans can understand.

104
TDD and continues refactoring
  • RedYou create a test that expresses what you
    expect your code to do. The test fails (turns
    red) because you haven't created code to make the
    test pass.
  • Green You program whatever is expedient to make
    the test pass (turn green). You don't pain
    yourself to come up with a duplication-free,
    simple, clear design at this point. You'll drive
    towards such a design later, when your test is
    passing and you can comfortably experiment with
    better designs.
  • RefactorYou improve the design of the code that
    passed the test.

105
TDD and continues refactoring
  • Keep defect counts low
  • Refactor without fear
  • Produce simpler, better code
  • Program without stress

106
Why should you refactor?
  • To make easier put in new code.
  • To improve the design of software.
  • To make software easier to undersand.
  • To make development more nice.
  • It helps you to find a bugs.
  • It helps you develop code more quickly.

107
When should you refactor?
  • The rule of three
  • The first time you do something, you just do it.
    The second time you do something similar, you
    wince at the duplication, but you do the
    duplicate thing anyway. The third time you do
    something similar, you refactor.

108
When should you refactor?
  • Refactor when you add function.Refactor to help
    you understand some code you need to
    modify.Refactor to change design that does not
    help you to add new feature easy.
  • Refactor when you need to fix a bug.
  • Refactor as you do a code review.
  • Design dept metphore and when shouldnt you
    refactor.

109
Refactoring and design
  • You still do upfront design, but now you don't
    try to find the solution. Instead all you want is
    a reasonable solution. You know that as you build
    the solution, as you understand more about the
    problem, you realize that the best solution is
    different from the one you originally came up
    with. With refactoring this is not a problem, for
    it no longer is expensive to make the changes.

110
Refactoring and design
  • Overdesign design that is more flexible than
    you need, it make project bigger and more
    complex.
  • Flexibility cost. With refactoring we move toward
    simplicity of design rather than flexibility.
  • You dont know now which changes you will need
    introduce to system in the future. Wrong
    predicted direction of changes make some
    flexibility newer used.
  • Emphasis on how difficult is it going to be to
    refactor a simple solution into the flexible
    solution?
  • Consciousness what you can refactor easy.

111
So what is the strategy
  • When you find you have to add a feature to a
    program, and the program's code is not structured
    in a convenient way to add the feature, first
    refactor the program to make it easy to add the
    feature, then add the feature.
  • Before you start refactoring, check that you have
    a solid suite of tests. Thus the refactoring
    should be self-checking.
  • Refactor the program in small steps. If you make
    a mistake, it is easy to find the bug.
  • Dont optimize ahead, concentrate on simplicity
    of design. Wait for result from diagnostics tools
    for optimization.

112
Bad smells in code
  • Duplicated codeExtract method, Extract class,
    Form Template Method, Introduce Polymorphic
    Creation with Factory Method, Chain Constructors,
    Replace One/Many Distinctions with Composite,
    Extract Composite, Unify Interfaces with Adapter,
    Introduce Null Object.
  • Long MethodExtract method, Introduce parameter
    object, Compose Method, Move Accumulation to
    Collecting Parameter, Replace Conditional
    Dispatcher with Command, Move Accumulation to
    Visitor,Replace Conditional Logic with Strategy

113
Bad smells in code
  • Conditional complexityReplace Conditional Logic
    with Strategy, Move Embellishment to Decorator,
    Replace State-Altering Conditionals with State,
    Introduce Null Object.
  • Primitive obsessionReplace data value with
    object, Replace type code with class, Replace
    State-Altering Conditionals with State, Replace
    Conditional Logic with Strategy, Replace Implicit
    Tree with Composite, Replace Implicit Language
    with Interpreter, Move Embellishment to
    Decorator, Encapsulate Composite with Builder

114
Bad smells in code
  • Indecent ExposureEncapsulate Classes with
    Factory
  • Solution SprawlMove Creation Knowledge to
    Factory
  • Alternative classes with different
    interfacesExtract superclass, Rename
    method,Unify Interfaces with Adapter
  • Lazy classCollapse HierarchyInline Singleton
  • Combinatorial explosionReplace Implicit Language
    with Interpreter
  • Oddball solutionUnify Interfaces with Adapter

115
Bad smells in code
  • Large classExtract class, Extract subclass,
    Extract interface,Replace Conditional Dispatcher
    with Command, Replace State-Altering Conditionals
    with State, Replace Implicit Language with
    Interpreter
  • Switch statementsExtract method, Replace type
    code with state/strategy, Replace conditional
    with polimorphism,Replace Conditional Dispatcher
    with Command, Move Accumulation to Visitor.

116
Simple refactorings
  • Support from development environment for
    automation of refactoring VS2008
  • Encapsulate field
  • Rename
  • Extract method
  • Extract Interface
  • Promote local variable to parameter
  • Remove parameters
  • Reorder parameters

117
Simple refactorings
  • Support from development environment for
    automation of refactoring R
  • Make a method (non)static
  • Push/pull members up/down
  • Replace constructor with Factory Method
  • Safe delete
  • Move type/static method

118
Self Encapsulate Field
  • You are accessing a field directly, but the
    coupling to the field is becoming awkward.
  • Create getting and setting methods for the field
    and use only those to access the field.
  • It allows a subclass to override how to get that
    information with a method and that it supports
    more flexibility in managing the data, such as
    lazy initialization, which initializes the value
    only when you need to use it.
  • You are accessing a field in a superclass but you
    want to override this variable access with a
    computed value in the subclass.
  • Make code more complicated.

119
Rename method
  • The name of a method does not reveal its purpose.
  • Change the name of the method.

120
Extract method
  • You have a code fragment that can be grouped
    together.
  • Turn the fragment into a method whose name
    explains the purpose of the method.
  • Pay attention to naming.
  • Do it allways when sematic distance between
    method body and method name is big.
  • It increases the chances that other methods can
    use a method when the method is finely grained
  • It allows the higher-level methods to read more
    like a series of comments.
  • Overriding also is easier when the methods are
    finely grained.

121
Extract method
  • No Local Variables
  • Using Local Variables (copy vs move)
  • Reassigning a Local Variable

122
Extract interface
  • Several clients use the same subset of a class's
    interface, or two classes have part of their
    interfaces in common.
  • Extract the subset into an interface.
  • Only a particular subset of a class's
    responsibilities is used by a group of clients or
    class needs to work with any class that can
    handle certain requests.
  • Class has a distinct roles in different
    situations. Make interface for each role.
  • You want to specify the outbound of the
    operations the class makes on its server.

123
Extract superclass
  • You have two classes with similar features.
  • Create a superclass and move the common features
    to the superclass.
  • Prevents code duplication by class inherence.

124
Extract subclass
  • A class has features that are used only in some
    instances.
  • Create a subclass for that subset of features.
  • Class has behavior used for some instances of the
    class and not for others.
  • Limitations
  • You can't change the class-based behavior of an
    object once the object is created.
  • You can change the class-based behavior with
    Extract Class simply by plugging in different
    components.
  • You can also use only subclasses to represent one
    set of variations.
  • If you want the class to vary in several
    different ways, you have to use delegation for
    all but one of them.

125
Pull up method
  • You have methods with identical results on
    subclasses.
  • Move them to the superclass.
  • Eliminate code duplication.
  • If method do the same but have different
    signatures unify signatures.
  • If method are similiar but not the same consider
    template method.
  • If two methods in different classes can be
    parameterized in such a way that they end up as
    essentially the same method then the smallest
    step is to parameterize each method separately
    and then generalize them.
  • If Pull Up Method body refer to features that are
    on the subclass but not on the superclass
    consider generalization that feature or creation
    an abstract feature in the superclass.

126
Move method
  • A method is, or will be, using or used by more
    features of another class than the class on which
    it is defined.
  • Create a new method with a similar body in the
    class it uses most. Either turn the old method
    into a simple delegation, or remove it
    altogether.
  • Do this if class has too much behaviour or when
    classes are collaborating too much and are too
    highly coupled.

127
Move method - mechanics
  • Examine all features used by the source method
    that are defined on the source class. Consider
    whether they also should be moved.
  • Check the sub- and superclasses of the source
    class for other declarations of the method.
  • Declare the method in the target class.
  • Copy the code from the source method to the
    target. Adjust the method to make it work in
  • its new home.
  • Compile the target class.
  • Determine how to reference the correct target
    object from the source.
  • Turn the source method into a delegating method.
  • Compile and test.
  • Decide whether to remove the source method or
    retain it as a delegating method.
  • If you remove the source method, replace all the
    references with references to the target method.
  • Compile and test.
  • R make method static/move/make method unstatic

128
Compose method
  • You can't rapidly understand a method's logic.
  • Transform the logic into a small number of
    intention-revealing steps at the same level of
    detail.
  • Efficiently communicates what a method does and
    how it does what it does.
  • Simplifies a method by breaking it up into
    well-named chunks of behavior at the same level
    of detail.
  • Can lead to an overabundance of small methods.
  • Can make debugging difficult because logic is
    spread out across many small methods.

129
Compose method - mechanics
  • Think small.
  • Remove duplication and dead code.
  • Communicate intention.
  • Simplify.
  • Use the same level of detail.

130
Replace Constructors with Creation Methods
  • There is a number of different, not trivial
    constructors
  • Creation Methods have meaningful names
  • Creation Methods can have identical parameters
  • Mechanics
  • Create Gathering Constructor (Chain Constructors)
  • Compile and Run
  • Find a constructor Call
  • Create a proprietary static method
  • Replace constructor calls with a method
  • Make the constructor private

131
Replace inherience with delegation
  • A subclass uses only part of a superclasses
    interface or does not want to inherit data.
  • Create a field for the superclass, adjust methods
    to delegate to the superclass, and remove the
    subclassing.
  • By using delegation instead, you make it clear
    that you are making only partial use of the
    delegated class. You control which aspects of the
    interface to take and which to ignore. The cost
    is extra delegating methods that are boring to
    write but are too simple to go wrong.
  • You need to use functionality or implementation?
  • Changing behaviour in runtime by changing
    reference to object which we use to delegate
    functionality.

132
Replace inherience with delegation mechanics
  • Create a field in the subclass that refers to an
    instance of the superclass. Initialize it to
    this.
  • Change each method defined in the subclass to use
    the delegate field. Compile and test after
    changing each method.
  • Remove the subclass declaration and replace the
    delegate assignment with an assignment to a new
    object.
  • For each superclass method used by a client, add
    a simple delegating method.
  • Compile and test.

133
Replace conditional with polymorphism
  • You have a conditional that chooses different
    behavior depending on the type of an object.
  • Move each leg of the conditional to an overriding
    method in a subclass. Make the original method
    abstract.
  • The biggest gain occurs when this same set of
    conditions appears in many places in the program.
  • Add a new case just by creation a new subclass
    and provide the appropriate methods.
  • Clients of the class don't need to know about the
    subclasses, which reduces the dependencies.

134
Replace type code with class
  • A class has a simple type code (int, String)
    that does not affect its behavior.
  • Replace the number with a new class.
  • A field's type fails to protect it from unsafe
    assignments and invalid equality comparisons.
  • Constrain the assignments and equality
    comparisons and provides better protection from
    invalid operations.
  • Compilation time detection for invalid
    operations.
  • If you replace the number with a class, the
    compiler can type check on the class. By
    providing factory methods for the class, you can
    statically check that only valid instances are
    created and that those instances are passed on to
    the correct objects.
  • If type code is not pure data but it affect state
    consider Replace type code with subclasses or
    Replace type code with State/Strategy.
  • Requires more code than using unsafe type does.

135
Replace type code with subclasses
  • You have an immutable type code that affects the
    behavior of a class.
  • Replace the type code with subclasses by creation
    a subclass for each type code.
  • To deal with presence of case-like conditional
    statements which test the value of the type code
    and then execute different code depending on the
    value of the type code or presence of features
    that are relevant only to objects with certain
    type codes.
  • Cooperates with Replace Conditional with
    Polimorphism, Push Down Method.
  • Problems when type code changes after the object
    is created or class with the type code is already
    subclassed for another reason. In that case
    consider Replace Type Code with State/Strategy.
  • It moves knowledge of the variant behavior from
    clients of the class to the class itself. Adding
    new variants is simply adding a subclass. Without
    polymorphism You have to find all the
    conditionals and change those. So this
    refactoring is particularly valuable when
    variants keep changing.

136
Replace type code with subclassesmechanics
  • Create a new class for the type code.
  • Modify the implementation of the source class to
    use the new class.
  • Compile and test.
  • For each method on the source class that uses the
    code, create a new method that uses the new class
    instead.
  • One by one, change the clients of the source
    class so that they use the new interface.
  • Compile and test after each client is updated.
  • Remove the old interface that uses the codes, and
    remove the static declarations of the codes.
  • Compile and test.

137
Replace type code with subclasses mechanics
  • Self-encapsulate the type code.
  • For each value of the type code, create a
    subclass. Override the getting method of the type
    code in the subclass to return the relevant
    value.
  • Compile and test after replacing each type code
    value with a subclass.
  • Remove the type code field from the superclass.
    Declare the accessors for the type code as
    abstract.
  • Compile and test.

138
Replace Type Code with State/Strategy
  • You have a type code that affects the behavior of
    a class, but you cannot use subclassing.
  • Replace the type code with a state object.
  • Self-encapsulate the type code.
  • Create a new class, and name it after the purpose
    of the type code. This is the state object.
  • Add subclasses of the state object, one for each
    type code.
  • Create an abstract query in the state object to
    return the type code. Create overriding queries
    of each state object subclass to return the
    correct type code.
  • Compile.
  • Create a field in the old class for the new state
    object.
  • Adjust the type code query on the original class
    to delegate to the state object.
  • Adjust the type code setting methods on the
    original class to assign an instance of the
    appropriate state objec
Write a Comment
User Comments (0)
About PowerShow.com