Some stuff about Web and .NET development
RSS icon Email icon Home icon
  • Dino Esposito @ Visug : C# 4.0 & testability

    Posted on October 17th, 2009 Thibaut 1 comment

    Visug

    This last 8th of October, Dino Esposito, a very well known figure in the .NET world, came to the Visug to talk about C# 4.0 and testability. Here’s a summary about the session :

    Software testability

    Code should ideally guarantee :

    • Visibility of the current state
    • Control degree at which code allows to send input data for testing purposes
    • Simplicity of the code results in more reliable test results

    Introducing the .NET 4.0 code contracts API

    The ecosystem at a glance

    1. Code contracts library
    2. Rewriter
    3. Static checker
    4. Contract reference generator

    1. Code contracts API

    3 basic types of contracts :

    1. Preconditions
    2. Postconditions
    3. Invariants

    Exposed via the contracts class (System.Diagnostics.Contracts)

    2. Rewriter

    • Translates contracts into code
    • Modifies MSIL instructions to place contracts checks where they logically belong
    • Executable is ccrewriter.exe

    3. Static checker

    • Examines code without executing it and tries to prove that all the contracts are satisfied
    • Lists unproven contracts to fix, otherwise you should debug or cover it with unit tests
    • Detects if there’s a possibility of contract violation

    4. Assembly reference generation

    • Extracts contract information from source code and returns an assembly with contract-only information
    • Used by rewriter & static checker
    • Executable is ccrefgen.exe

    Steps of a method

    1. Check validity of parameters & stats
    2. Do real work
    3. Check of existing works
    4. Update state accordingly

    Set up

    1. Add reference to mscorlib
    2. Contract must be specified in the body of the methods
    3. Contracts are not mandatory. You can do without

    Preconditions, postconditions and invariants

    Preconditions

    • Requires(bool condition)
    • Requires<TException>(bool condition) throws an exception if condition is not met
    • if-then-throw statements
    • RequiresAlways(bool condition) is like Requires but stripped off in retail builds

    Postconditions

    • Ensures(bool condition), condition must be true at the end of the method
    • EnsuresOnThrow<TException>(bool condition), condition must be true if exception is thrown. Allows for checks even if exceptional return arises (network error, stack overflow, …)
    • Helper methods
      • Result<T>()
      • OldValue<T>(T variable)
      • ValueAtReturn<T>(out T variable)

    Invariants

    • Invariant(bool condition), object-wide condition that must hold for the lifetime of the class
    • All invariants for a class are defined in one place

    Best practice :

    • Define invariants before implementing the class
    • Express the conditions under which the object is in good state
    • Could be hard to add them at a later time

    Assert & assume

    • At runtime, fully equivalent to Debug.Assert
    • Static checker attemps to prove any Assert, emitting a warning if it fails
    • Static checker treats Assume as always true, adds the assumption to its collection of facts

    Quantifiers

    • Used to iterate a check on all elements of a list
    • ForAll(…), true if condition is met by all elements
    • Exists(…)

    Interface contracts

    • Define a separate class for the contract because we can’t add code to interface memebers (no mixins in C#)
    • Link to the interface via attribute

    Contracts & inheritance

    Contracts are inherited by derived classes, regardless wether you invoke base class methods in overrides

    Code contracts & debugging

    • When failure, contract raises
      • ContractFailedException
      • ContractFailedEventArgs
    • No default handler (thrown everytime)
    • Register handler to ContractFailedException at startup (Global.asax for ASP.NET, Main method for WinForms)

    Contract failures & unit tests

    • You don’t want contract exceptions in unit tests
    • Rather want exceptions to be reported as tests failures
    • SetHandled() to let assume exception has been handled and SetUnwind() to clear the stack

    Summary

    • Code contracts as part of the design effort
    • Adds testability to classes & code
    • New API coming up in C# 4.0

    And one final important quote of Dino Esposito :

    “Testable code means that it exposes every significant part of it in order to check its correct behaviour”

    See you next time ;)

    Share/Save/Bookmark