1

I want to test the simplest case : testing a mocked strategy object. (look at : Strategy pattern).

If I create a TMock<T> in the TTestCase.setUp methods and store it in a TTestCase instance attribute, then should I free/NIL the mock variable in the tearDown method?

The mock := NIL does not compile:

[dcc32 Error] TestUnit2.pas(44): E2010 Incompatible types: 'Delphi.Mocks.TMock<T>' and 'Pointer'.

The mock.free runs without any error, but I'm not sure I should call it. The mock released when the process exits its scope (after test case destructor).

Should I call/set anything?

The code:

Unit2.pas:

unit Unit2;

interface

type
  TPartClass = class
  public
    function foo( x_ : integer ) : integer; virtual;
  end;

  TMainClass = class
  private
    fPart : TPartClass;
  public
    constructor create( part_ : TPartClass );

    function bar( x_ : integer ) : integer;
  end;

implementation

function TPartClass.foo( x_ : integer ) : integer;
begin
  result := x_ shl 1;
end;

constructor TMainClass.create( part_ : TPartClass );
begin
  inherited create;
  fPart := part_;
end;

function TMainClass.bar( x_ : integer ) : integer;
begin
  result := fPart.foo( x_ );
end;

TestUnit2.pas:

unit TestUnit2;

interface

uses
  Delphi.Mocks, TestFramework, Unit2;

type
  TTestTMainClass = class(TTestCase)
  strict private
    fPartClass : TMock<TPartClass>;
    FMainClass: TMainClass;
  public
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure Testbar;
  end;

implementation

procedure TTestTMainClass.SetUp;
begin
  fPartClass := TMock<TPartClass>.create;
  FMainClass := TMainClass.Create( fPartClass );
end;

procedure TTestTMainClass.TearDown;
begin
  FMainClass.Free;
  FMainClass := NIL;
  //fPartClass.Free;
  //fPartClass := NIL;
end;

procedure TTestTMainClass.Testbar;
var
  ReturnValue: Integer;
  x_: Integer;
begin
  fPartClass.Setup.WillReturn( 10 ).When.foo( 5 );
  x_ := 5;
  ReturnValue := FMainClass.bar(x_);
  checkTRUE( returnValue = 10 );
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
The Bitman
  • 1,279
  • 1
  • 11
  • 25

1 Answers1

2

You should always cleanup everything in TearDown that you created during SetUp. Even though things might be cleaned up later it is good practice and will enable you to look for resource leaks while unit testing.

Since TMock<T> is a record that internally holds interfaces you need to make sure those are cleaned up after the test run although they might be overridden by the next SetUp or when the testcase instance gets destroyed.

That is what .Free is for (despite the comment in the source)

This is even more important once you do more complex things with the mock as it might keep things alive or point to invalid references after the test. I have seen some bad crashes at the end of test applications that did not clean up their mocks.

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
  • OK. I hoped that I should do it. If object A create object B then it should dispose it. I will uncomment the mock.free again. But how can I set it to NIL after free? The compiler unable to interpret it. Thanks for your fast answer. Confusion explanation : I read your comment about auto released mocks created and passed back in unnamed functions (before I posted my question). (I can't find it again). I was confused. Maybe the TestCase instance scope will dispose it in the same way. – The Bitman Mar 14 '17 at 16:21
  • I found it again : http://stackoverflow.com/questions/27874168/mocking-interfaces-in-dunit-with-delphi-mocks-and-spring4d What is the difference in the two cases? (him and my) – The Bitman Mar 14 '17 at 16:30
  • The scope of the mock. It's a local variable in that other issue and thus goes out of scope which causes finalization (setting internal interfaces to nil which causes destruction of the objects behind those interfaces). Yours is a field in the testcase instance and lives as long as that instance lives. – Stefan Glienke Mar 14 '17 at 16:34
  • OK. I mock class instance and not an interface! And just outscoped interfaces released automatically. I got it at last! :) And what about the mock := NIL after mock.free? I'm unable to cast it in a way the compiler accept it. – The Bitman Mar 14 '17 at 16:44
  • What's with that setting to nil obsession. It's a record. – Stefan Glienke Mar 14 '17 at 16:51
  • "OK. I mock class instance and not an interface!" Irrelevant - I was talking about the mock internals which are interfaces. – Stefan Glienke Mar 14 '17 at 16:52
  • What kind of records do you mean? It is a TMock. If I write it: fPartClass := TMock( NIL ); The compiles says. Invalid typecast. – The Bitman Mar 14 '17 at 16:56
  • 2
    @TheBitman `TMock` is a **record**, not a **class**. The `TMock` instance is not being dynamically allocated, so there is no pointer to nil. The record has a `Free` method to clean up its data fields. That is all you need. – Remy Lebeau Mar 14 '17 at 17:02