Search code examples
delphidelphi-xe2spring4d

Testing a class not declared in the interface section


I'm a newbie with Dependency Injection containers, and I am trying to get my head around using them in conjunction with Mocking.

Lets say I have a controller and a list (the model):

IBlahList = interface
  property Items[AIndex: integer]: IBlah read GetItem;
end;

IController = interface
  property List: IBlahList read GetList;
end;

The implementation of IController would look something like (note, it's in the implementaion section:

implementation

TController = class (TInterfacedObject, IController)
private
  FList: IBlahList;
  function GetList: IBlahList;

public
  constructor Create(const AList: IBlahList);

end;

And then, of course, I would register this class (as well as one for IBlahList) with the GlobalContainer:

GlobalContainer.RegisterType<TController>.Implements<IController>;

I place the TController in the implementation section, as suggested by various sources (well, Nick Hodges anyway!), so that we cannot reference the TController class directly.

Now, just say I want to test my implementation of ICollection in a unit test:

procedure TestSomething
var
  LMockList: TMock<IBlahList>;
  LController: IController;
begin
  LMockList := TMock<IBlahList>.Create;

  // Oops, I can't do this, I can't access TController
  LController := TController.Create(LMockList);

end;

So, my question is, should I move the TController class into my interface section so I can test it, or is there some other way to pass the mock IBlahList to the controller that I have yet to find?


Solution

  • If you have the concrete class in the implementation section, then you could expose a factory function (i.e. have it in the interface section) that creates an IController with the required parameters.

    It makes absolutely no sense to have an implementation that can not be instantiated, IMO.

    interface
    
    ...
    
    function CreateController(AList: IBlahList): IController;
    
    implementation
    
    function CreateController(AList: IBlahList): IController;
    begin
      Result := TController.Create(AList);
    end;