2013-10-30 18 views
1

我有以下接口:不滿意依賴異常德爾福XE2

unit uICodec; 

interface 
uses UITypes,uTPLb_CryptographicLibrary ; 

type 
    ICodec = interface 
    ['{B1858F24-5B76-4468-8BD5-55684EA43CCD}'] 
    procedure EncryptString(const Plaintext: string; var CipherText_Base64: 
     ansistring); 
    procedure DecryptString(var Plaintext: string; const CipherText_Base64: 
     ansistring); 
    function RCGL:TCryptographicLibrary; 
    procedure WCGL(const c:TCryptographicLibrary); 
    property CryptoLibrary:TCryptographicLibrary read RCGL write WCGL; 
    function RSCI:string; 
    procedure WSCI(const c:string); 
    property StreamCipherId:string read RSCI write WSCI; 
    function RBCI:string; 
    procedure WBCI(const c:string); 
    property BlockCipherId:string read RBCI write WBCI; 
    function RCMI:string; 
    procedure WCMI(const c:string); 
    property ChainModeId:string read RCMI write WCMI; 
    function RPWD:string; 
    procedure WPWD(const c:string); 
    property Password:string read RPWD write WPWD; 
    end; 

與它相關的模擬類,其中功能/程序沒有做任何事情:

unit uMockTPWDDBManager; 

interface 

uses classes,uTPLb_CryptographicLibrary,uICodec,UITypes; 

type 

    TMockCodec1 = class(TInterfacedObject,ICodec) 
// constructor Create (Aowner: TComponent); 
    procedure EncryptString(const Plaintext: string; var CipherText_Base64: 
     ansistring); 
    procedure DecryptString(var Plaintext: string; const CipherText_Base64: 
     ansistring); 
    private 
    function RCGL:TCryptographicLibrary; 
    procedure WCGL(const c:TCryptographicLibrary); 
    function RSCI:string; 
    procedure WSCI(const c:string); 
    function RBCI:string; 
    procedure WBCI(const c:string); 
    function RCMI:string; 
    procedure WCMI(const c:string); 
    function RPWD:string; 
    procedure WPWD(const c:string); 
    end; 
.... 
function TMockCodec1.RBCI: string; 
begin 

end; 
... 
initialization 
    GlobalContainer.RegisterComponent<TMockCodec1>.Implements<ICodec>; 
end. 

當我嘗試運行使用下面的代碼測試,我有錯誤

procedure TestTPWDDBManager.SetUp; 
begin 

GlobalContainer.Build; 
    FCodec1:=ServiceLocator.GetService<ICodec>;//EUnsatisfiedDependencyException with message 'Unsatisfied dependency for the service "ICodec" 

我重複檢查和所有的程序/ f ICodec中的強制與TMockCodec1中的強制相同。

我在哪裏錯了?

[更新]

我跟大衛的建議,我想,我已經找到了錯誤。我.dpr是以下幾點:

uses DUnitTestRunner, 
uMockTPWDDBManager in 'uMockTPWDDBManager.pas', 
uTCodec1 in '..\uTCodec1;.pas'; 

單元uMockTPWDDBManager有以下初始化:

... 
initialization 
    GlobalContainer.RegisterComponent<TCodec1>.Implements<ICodec>; 
end. 

和單位uTCodec1有以下初始化:

initialization 
    GlobalContainer.RegisterComponent<TMockCodec1>.Implements<ICodec>; 

當我刪除uTCodec1從。 dpr的錯誤信息消失了。

我認爲相同接口的兩個初始化不能共存於同一個.dpr中。

我正確嗎?

[SSCCE]

不幸的是,我能夠向下降低單位數只3。

以下是.dpr

program TPWDDBManager; 
{ 

    Delphi DUnit Test Project 
    ------------------------- 
    This project contains the DUnit test framework and the GUI/Console test runners. 
    Add "CONSOLE_TESTRUNNER" to the conditional defines entry in the project options 
    to use the console test runner. Otherwise the GUI test runner will be used by 
    default. 

} 

{$IFDEF CONSOLE_TESTRUNNER} 
{$APPTYPE CONSOLE} 
{$ENDIF} 

uses 
    DUnitTestRunner, 
    TestuTPWDDBManager in 'TestuTPWDDBManager.pas', 
    uTPWDDBManager in '..\uTPWDDBManager.pas'; 

{$R *.RES} 

begin 
    DUnitTestRunner.RunRegisteredTests; 
end. 

這是第一個單元:

unit uTPWDDBManager; 

interface 

uses IniFiles,uICodec,UITypes; 

type 
    ICodec = interface 
['{B1858F24-5B76-4468-8BD5-55684EA43CCD}'] 
    procedure EncryptString(const Plaintext: string; var CipherText_Base64: 
     ansistring); 
    procedure DecryptString(var Plaintext: string; const CipherText_Base64: 
     ansistring); 
end; 

    IInsertPassword = interface 
    ['{B197F2EE-8C65-4E59-897F-F69E6E8D252F}'] 
    function ShowModal: Integer; 
    function GetOldPWD : String; 
    function GetNewPWD : String; 
    end; 

    IMessageDlg = interface 
    ['{5A527174-50D4-4BB9-8E9F-6A9926B2893C}'] 
    function MessageDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: 
     TMsgDlgButtons;HelpCtx: Longint): Integer; 
    end; 

    IPWDDBManager = interface 
    ['{51C993FE-D96A-4419-AB80-00D65E16C6F8}'] 
    function GetDBPWD (const Key : string; var Reset : Boolean): string; 
    function ChangePWD (OldKey, NewKey : string): string; 
    procedure Reset; 
    end; 

    TPWDDBManager=class(TIniFile,IPWDDBManager) 
    private 
    FRefCount: Integer; 
    protected 
    function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall; 
    function _AddRef: Integer; stdcall; 
    function _Release: Integer; stdcall; 
    public 
    constructor Create(const FileName: string; Fcodec: ICodec ; 
     meggagedlg: IMessageDlg);virtual; 
    function GetDBPWD (const Key: string; var Reset: Boolean): string; 
    function ChangePWD (OldKey, NewKey : string): string; 
    procedure Reset; 
    property RefCount: Integer read FRefCount; 
    end; 

implementation 

uses Dialogs, SysUtils,Spring.container; 

{ TPWDDBManager } 

function TPWDDBManager.ChangePWD (OldKey, NewKey : string): string; 
begin 
end; 

constructor TPWDDBManager.Create(const FileName: string; Fcodec: ICodec ; 
    meggagedlg: IMessageDlg); 
begin 
end; 

function TPWDDBManager.GetDBPWD (const Key : string; var Reset : Boolean): string; 
begin 
    result:=''; 
end; 

function TPWDDBManager.QueryInterface(const IID: TGUID; out Obj): Integer; 
const 
    E_NOINTERFACE = $80004002; 
begin 
    if GetInterface(IID, Obj) then 
    Result := 0 
    else 
    Result := E_NOINTERFACE; 
end; 

procedure TPWDDBManager.Reset; 
begin 
end; 

function TPWDDBManager._AddRef: Integer; 
begin 
end; 

function TPWDDBManager._Release: Integer; 
begin 
end; 

end. 

,這是第二個:

unit TestuTPWDDBManager; 
    { 

     Delphi DUnit Test Case 
     ---------------------- 
     This unit contains a skeleton test case class generated by the Test Case Wizard. 
     Modify the generated code to correctly setup and call the methods from the unit 
     being tested. 

    } 

     interface 

     uses TestFramework,IniFiles,classes,UITypes,uTPWDDBManager; 

     type 

     tcodec1=class(tcodec) 

     end; 


      TMockCodec1 = class(TInterfacedObject,ICodec) 
      procedure EncryptString(const Plaintext: string; var CipherText_Base64: 
       ansistring); 
      procedure DecryptString(var Plaintext: string; const CipherText_Base64: 
       ansistring); 
      end; 

      TMockInsertPassword1 = class(TInterfacedObject,IInsertPassword) 
      constructor create (Aowner: TComponent); 
      function ShowModal: Integer; 
      function GetOldPWD : String; 
      function GetNewPWD : String; 
      end; 

      TMockMessagedlg = class(TInterfacedObject,IMessageDlg) 
      function MessageDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: 
       TMsgDlgButtons;HelpCtx: Longint): Integer; 
      end; 

      // Test methods for class TPWDDBManager 

      TestTPWDDBManager = class(TTestCase) 
      strict private 
      FCodec1: ICodec; 
      FPWDDBManager: IPWDDBManager; 
      Inifile:TInifile; 
      mockmessagedlg:IMessageDlg; 
      ReturnValue: string; 
      public 
      procedure SetUp; override; 
      procedure TearDown; override; 
      published 
      procedure TestGetPWD; 
      end; 

     implementation 

     uses SysUtils,Spring.container,Spring.Services; 

     procedure TestTPWDDBManager.SetUp; 
     begin 
      GlobalContainer.Build; 
      FCodec1:=ServiceLocator.GetService<ICodec>; 
      mockmessagedlg:=ServiceLocator.GetService<IMessageDlg>; 
      FPWDDBManager :=TPWDDBManager.Create(ChangeFileExt((ParamStr(0)),'.ini'), 
      FCodec1,mockmessagedlg); 
     end; 

     procedure TestTPWDDBManager.TearDown; 
     begin 
      Inifile.Free; 
     end; 

     procedure TestTPWDDBManager.TestGetPWD; 
     var 
      reset: boolean; 
     begin 
     //// this instruction deletes a .ini file /// 
      DeleteFile(ChangeFileExt((ParamStr(0)),'.ini')); 
      ReturnValue := FPWDDBManager.GetDBPWD('a',reset); 
      CheckEqualsString(ReturnValue,''); 
      // TODO: Validate method results 
     end; 

     procedure TMockCodec1.DecryptString(var Plaintext: string; 
      const CipherText_Base64: ansistring); 
     begin 
     Plaintext:=StringReplace(string(CipherText_Base64),'encripted','decripted',[ 
      rfReplaceAll,rfIgnoreCase]); 
     end; 

     procedure TMockCodec1.EncryptString(const Plaintext: string; 
      var CipherText_Base64: ansistring); 
     begin 
      CipherText_Base64:=ansistring(StringReplace(Plaintext,'decripted','encripted',[ 
      rfReplaceAll,rfIgnoreCase])); 
     end; 

     { TMockInsertPassword1 } 

     constructor TMockInsertPassword1.create(Aowner: TComponent); 
     begin 
     end; 

     function TMockInsertPassword1.GetNewPWD: String; 
     begin 
      result:='new pwd decripted'; 
     end; 

     function TMockInsertPassword1.GetOldPWD: String; 
     begin 
      result:='old pwd encripted'; 
     end; 

     function TMockInsertPassword1.ShowModal: Integer; 
     begin 
      result:=1; 
     end; 

     { TMockMessagedlg } 

     function TMockMessagedlg.MessageDlg(const Msg: string; DlgType: TMsgDlgType; 
      Buttons: TMsgDlgButtons; HelpCtx: Integer): Integer; 
     begin 
      result:=-1; 
      if Msg='File ' + 
      'E:\Delphi\Projects\Components\Tests\TPWDDBManager\TestFolder\Win32\Debug\.ini doesn''t exists' then 
      result:=1 
      else if Msg='File ' + 
      'E:\Delphi\Projects\Components\Tests\TPWDDBManager\TestFolder\Win32\Debug\.ini doesn''t exists' then 
      result:=2 
     end; 

     initialization 
      // Register any test cases with the test runner 
      RegisterTest(TestTPWDDBManager.Suite); 
      GlobalContainer.RegisterComponent<TMockCodec1>.Implements<ICodec>; 
      GlobalContainer.RegisterComponent<tcodec1>.Implements<ICodec>; 
GlobalContainer.RegisterComponent<TMockInsertPassword1>.Implements<IInsertPassword>; 
      GlobalContainer.RegisterComponent<TMockMessagedlg>.Implements<IMessageDlg>; 
     end. 

我可以編譯源,但是當我運行測試我有錯誤消息EUnsatisfiedDependencyException與消息'服務的不滿意的依賴項「ICodec」

如果我刪除類tcodec1並刪除GlobalContainer.RegisterComponent<tcodec1>.Implements<ICodec>; 則沒有更多的錯誤消息。

是否因爲您不能在同一個項目中註冊多個類並引用相同的接口?

+0

不熟悉Delphi如何嘲笑,但是你在界面聲明中列出的幾個方法比你在模擬中顯示的還要多。 –

+0

您是否將單元uMockTPWDDBManager顯式包含在TestTPWDDBManager所在單元的uses子句中? – Jason

+0

此外,GLobalContainer.Build只需要調用一次,所以你可以(應該不知道)將它移動到.dpr文件 - 我通常將它放在Initialize方法調用後 – Jason

回答

0

如果您有多個相同服務類型的註冊,則應使用不同的名稱註冊這些註冊。否則,如果調用Resolve/GetService,容器無法決定返回哪一個。

我想給單元測試的另一個建議:不要在那裏使用容器,而是手動連接你需要的依賴關係(即模擬)。在你的例子中,它甚至沒有意義,因爲你沒有讓容器構造你的系統在測試中(所以它可以注入你嘲笑的任何依賴)。

如果您使用trunk的最新版本,則在註冊多個未命名服務時不應再發生錯誤。但它將返回服務的最後一個註冊組件(或最後一個您稱爲.AsDefault的組件)。這將最有可能改變,所以我的第一個建議仍然存在(如果你有多個,使用命名註冊)。

+0

最新版本可以在以下地址找到嗎? :http://delphi-spring-framework.googlecode.com/svn/trunk/ –

+1

該項目現在託管在這裏:https://bitbucket.org/sglienke/spring4d –