我有以下界面:
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"
我仔细检查过,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>;
当我从 .dpr 中删除 uTCodec1 时,错误消息消失了。
我认为同一个接口的两个初始化不能在同一个.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>;
则不再有错误消息。
是不是因为你不能在同一个项目中注册多个类并引用同一个接口?