Archive

Posts Tagged ‘TDD’

GUI testing with DUnit

February 2nd, 2009

I don’t how I didn’t know this until now but it turns out there’s a whole section of DUnit designed to help you test GUI elements. What follows is small write up about how to do it. Read more…

XP , , , ,

RE: Architectural Hedges

January 7th, 2009

Craig Stuntz recently posed the question of how to build hedges into our products and processes.

If I understand the problem correctly what we want is a way to mitigate the risk of choosing the wrong technology or technique. This is to say if we do choose the wrong technology or technique (for whatever reason) how do we recover and change direction with a minimal amount of fuss and cost.

I think the biggest guiding princple we have for this is Deferred Implmentation. Deferred Implementation demands implementation agnosticism from the client code. We’ll use the User Repository code from the post Keep you code lazy and ignorant as an example. When we wrote the code that needed to look up a user by the user name the client code was ignorant of how the data got there. This was good because it meant we could focus on the business logic of logging in and leave the details of how retrieve user information for later. All we needed to supply was an API for the client code to use. Later, in the next post, we wrote the code to retrieve the user data using an ADO connection to a SQL database. The truth is we could have used any storage medium like an XML file or web service. Either way the client code didn’t change because of the implementation details in the User Repository. Doing this created a hedge in both the barrier sense and the risk mitigation sense.

TDD played a big role in getting to the deferred implementation of the User Repository. We were able to quickly put together a test bed for our ideas and keep it to be sure we didn’t inadvertently break anything. TDD also gave us a formula for the incremental improvement of the code.

TDD by itself didn’t get the job done. We needed to be conscious of separation of concerns, not mixing object creation with business logic and design patterns that help us solve these sorts of problems.

I hope this addressed the question Craig posed. If not, I hope this was at least informative.

XP , ,

Keep your code ignorant and lazy!

November 26th, 2008

This post is a follow up to Busting the great TDD Myth. If you haven’t already read it, please check it out.

Lets review the code from the last post:

function TLogin.GetConnectionString : string;
var
  reg : TRegIniFile;
begin
  reg := TRegIniFile.Create('Software\MyApp');
  Result := reg.ReadString('Database', 'ConnectionString', '');
  FreeAndNil(reg);
end;
 
function TLogin.Execute(const UserName, Password : string) : Boolean;
var
  UserQuery : TADOQuery;
  DBUserPassword : string;
begin
  UserQuery := TADOQuery.Create(nil);
  try
    UserQuery.ConnectionString := GetConnectionString;
    UserQuery.SQL.Text := 'SELECT Password FROM Users WHERE UserName = ' + 
                         QuotedStr(UserName);
    UserQuery.Open;
    DBUserPassword := UserQuery.FieldByName('Password').AsString;
    UserQuery.Free;
    Result := DBUserPassword = Password;
  except
    Result := False;
  end;
end;

Now lets review the problems:

  • Hidden dependencies - TLogin does not publish the fact that it relies on a connection to the database and needs a connection string from the registry.
  • Mixing concerns - Business logic and object creation occur in the same block of code. This means you can’t test business logic without creating the dependencies.



All of these problems can be summed up as: Too much ceremony and too little essence. What is this class trying to do? Does creating a connection to the database, querying a table and handling exceptions have much to do with the purpose of logging in to the system?

Read more…

XP , , , ,

Busting the great TDD myth

November 20th, 2008

WARNING
There’s a lot going on in this article. It is intended to be humorous and slightly inflammatory. It’s also the first of a series. I intend to show you how the average Joe digs himself into a hole and then how to get out. I hope you enjoy the read.

On with the show …

You will not learn what you need to know from a TDD course/book/lecture. When you walk away you will not be able to write better software. You will not be able to test drive all your code in a fully automated test suite. Your expectations will not be met and you will quickly dump the whole concept of Test Driven Development.

It’s true.

The problem has nothing to do with TDD. The problem is that you don’t know how to write better software. TDD will not make you a coding rock star. You will not be the envy of your peers. Your face will not be printed on a t-shirt (I don’t think that’s ever happened but it would be cool).

Read more…

XP , ,

TDD’ing the GUI

July 31st, 2007

Can’t be done, right?

We have some patterns that help us do this: MVP, Passive View, Supervising Controller, Presenter First. Rolling your own implementation of these patterns is challenging and time consuming. Additionally, we haven’t had any frameworks to make it any easier.

So that’s the problem I set out to solve. I’ve reached a point where I’ve been able create a proof of concept application with this framework I’ve been writing. I’m hoping to get some feedback from the community on this.

So what did I do?

I chose to solve the problem using the Passive View pattern. I wanted to be able to design a form with the Delphi form designer but I didn’t want to put any code in the form implementation. That left me with the problem of controlling the GUI from the controller object. Since the point of this exercise is to keep everything testable from a unit test I couldn’t have the controller interacting with the concrete GUI elements. So I came up with the following:


IView = interface
  GetViewElement(const ID : string) : IViewElement;
end;

IView has the responsibility of providing access to the view elements to the controller. So the controller can interact with these IViewElement interfaces instead of the concrete GUI elements (like TButton, TEdit, etc.).

What I didn’t want is to have to use special VCL components to make this work. First, because it would be too much trouble to create a full suite of components that implemented IViewElement and second because I wanted to be able retro fit an existing application to this style of design. To accomplish this I did the following:

TGuiAdaptor = class(TInterfacedObject, IViewElement)
public
  constructor Create(AControl : TControl)
end;

In GetViewElement the concrete view wraps concrete GUI elements with the TGuiAdaptor and returns it to the controller. So now we can choose to mock the view or, more appropriately to the purpose, use the concrete view for testing.

Having got this far I can now use TDD to express behavioral requirements in the form of unit tests. Have a look at the demo application included in the archive.

Why would I do this?

  1. I find that using TDD produces better code faster
  2. Automated testing has been my friend :)
  3. I hope I can convince someone at CodeGear that this is style of development is a Good Thing ™ and to enable the IDE to directly support this type of development

Be aware: This is a proof of concept release. I know there’s a great deal more work to go before this would be viable for production.

Here is the code: PassiveViewFramework.rar

TDD, XP , , ,