6

I have several little functions in an old Unit called Utils.pas.

Now I'd like refactoring some of them, but I think it's better to write test before. With DUnit I think it's impossible without a class.

So I'd like to know how can I test them before refactoring?

Edit:

I thought it was impossible because I was trying to add a test case in Delphi using Test Case Wizard. See the picture bellow that there aren't any classes and methods, so I'm not be able to create it.

enter image description here

Daniel Grillo
  • 2,368
  • 4
  • 37
  • 62
  • 3
    The wizard will only "look" at class methods. Standalone methods will have to be tested "by hand", i.e., you'll have to manually write the code yourself. – Nick Hodges Jun 14 '11 at 12:58
  • 3
    It's hard to imagine what use this wizard would be. What a waste of effort in developing it. – David Heffernan Jun 14 '11 at 13:33
  • @David: it could save some time because it creates stubs for all test methods. I don't find these stubs very useful though, so I mostly create them by hand anyway. – jpfollenius Jun 14 '11 at 13:50
  • 1
    The wizard is quite useless imho. If you follow a TDD approach, you write a test before you implement the production code. However, one would think generating stubs for existing code that isn't yet tested would be a great time-saver. Unfortunately, the wizard assumes a 1-1 relationship between methods of a class and the tests which is absolutely not the case. Ironically there's more chance of a single test being sufficient when writing tests for flat functions than for methods of objects. – Disillusioned Jun 14 '11 at 15:44

3 Answers3

8

AFAICT, DUnit does not require code under test to exist as class methods. Only the test cases themselves must be classes.

EDIT: The wizard is just a convenience. You don't have to use it.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
7

You can't test a standalone function using the wizard but it's not a problem to test a standalone function with DUnit.

Example

  //***** A Standalone function te be tested in a unit far, far away
  function Add(v1, v2: Integer): Integer;
  ...

  //***** A testclass to contain the testmethods calling our 
  //      standalone function     
  TTestAdd = class(TTestcase)
  published
    procedure AddingComplement_ShouldEqualZero;
    procedure AddingNegativeNumbers_ShouldBeLessThanZero
    ...
  end;

  implementation

  procedure TTestAdd.AddingComplement_ShouldEqualZero;
  begin
    // Setup, Execute & Verify
    CheckEquals(0, Utils.Add(-1, 1), 'Complement doesn''t add to zero');
  end;

  procedure TTestAdd.AddingNegativeNumbers_ShouldBeLessThanZero
  begin
    // Setup, Execute & Verify
    CheckEquals(-3, Utils.Add(-1, -2), 'Add doesn''t add');
  end;
Lieven Keersmaekers
  • 57,207
  • 13
  • 112
  • 146
1

Real code needs to be maintained. Real code has assumptions that are not well documented. Real code is changed by people who forget or never knew those assumptions. Trust the tests, dont trust the code.

Real TDD allows you to create the object and its methods before implementation. You need a clear model before you can write a test case anyway.

So generate the object(s), add the methods, parameters etc. Probably using UML2 would be best, then write the test cases for those, and then implement the objects. After that run the profiler and find out how horrible your code really is, and refactor.

As a general solution it is almost always best to write a factory object to instantiate and initialize your objects. The closer you get to core functionality the more this becomes important.

Write tests for your expected failures and exceptions. use a check to make sure.

Finally write each test and watch it fail before you write the code to make it succeed.

Michael
  • 587
  • 3
  • 14