Blog from August, 2009

Quality and testing

Introduction

DelftShell is becoming a framework in which desktop applications throughout Deltares can be embedded. For this to happen the quality of the framework should meet high standards. In order to achieve these high standards we need sourcecode that is well tested. To achieve this goal we would like to suggest the following improvements to the test procedure

Committed testers and developers

make sure we have committed testers, that are a member of the team. Testers should attend planning sessions, cool down sessions and should work side by side with developers. It would also be good if they could attend the standup sessions. Often a tester could sit next to a developer so the developer can make small changes on the fly and identify larger issues for review of the product owner. Issues reported by testers should be dealt with quickly.

Unit test coverage

Unit test coverage of DelftTools and DelftShell are now at about 32%. This number should be raised to at least 70% for DelftTools and maybe 50% for DelftShell. Each member of the team should write some unit tests for DelftShell or DelftTools classes that are being used in the code he is currently modifying. It is recommended to install testdriven.net or ncover so the developers can see areas of sourcecode that are not sufficiently tested.

User stories and tasks

Definition of done should be extended so that when a developer adds some new functionality it should have sufficient test coverage.

ValidationAspects

ValidationAspects looks to be a very nice library. Wery well tested with ~100% test coverage and wrapped with PostSharp (as a separate dll).
I've checked it into lib/ - use it on all Entities to set validations.

[Validate]
public class Customer
{
  private string _email;

  // apply validation to property setters
  [NotNullOrEmpty] public string Name { get; set; }
  [Minimum(0)] public int Age { get; set; }

  // apply validation to method parameters
  public void SetEmail([NotNullOrEmpty] string email) { _email = email; }

  // provide validation for objects either with methods or declaring validators on the class
  [ValidationMethod]
  public static void ValidateEmail(Customer customer)
  {
    if (string.IsNullOrEmpty(customer._email))
      throw new ValidationException("Email is not valid");
  }
}

Programmatic Registration:

// register lambda syntax validation functions
typeof(User).GetProperty("Name").AddValidation<string>((name, context) => { if (!Exists(name)) { throw new ValidationException("Username is unknown"); } } );

// register validation factories (classes)
typeof(User).GetProperty("Name").AddValidation(new [] { new NotNullOrEmpty()} );

// don't like strings?
TypeOf<User>.Property(user => user.Name).AddValidation(new [] { new NotNullOrEmpty()} );

Object Validation:

ValidationResult result = customer.Validate();
if (!result.IsValid)
{
  foreach (string message in result.Messages) { ... }
}
Understanding multidimensional arrays

Useful links: