spring4d 注销接口类型(spring4d、dunitx、delphi-mocks)
spring4d unregister interface type (spring4d, dunitx, delphi-mocks)
我正在使用 spring4d、dunitx 和 delphi-mocks 编写我的第一个单元测试。
(spring4d 版本 1.1 - 12.09.2014)
在我的测试应用程序中,我自动将一个接口注入到我的被测系统 class (sut):
IMyInterface = interface [{yes, a GUID here}]
function GetSomething1: TSomething1;
function GetSomething2: TSomething2;
end;
TMyClass = class
private
[Inject]
FMyInterface: IMyInterface;
// ...
end;
现在,当我使用带有模拟的单元测试时,我使用以下(非常简单的)代码:
TMyTest = class
private
[Test]
procedure Test1;
[Test]
procedure Test2;
// ...
end;
procedure TMyTest.Test1;
var
aSut: TMyClass;
aIntfMock: TMock<IMyInterface>;
aSomething1: TSomething1;
begin
// Arrange
GlobalContainer.RegisterType<TMyClass>;
aIntfMock := TMock<IMyInterface>.Create;
try
GlobalContainer.RegisterType<IMyInterface>.DelegateTo(
function: IMyInterface
begin
Result := aIntfMock;
end)
.AsDefault;
GlobalContainer.Build;
aSomething1 := TSomething1.Create;
try
aIntfMock.Setup.WillReturn(TValue.From<TSomething1>(aSomething1)).When.GetSomething1;
aSut := GlobalContainer.Resolve<TMyClass>;
try
// Act
aSut.DoSomething;
finally
FreeAndNil(aSut);
end;
// Assert
// ...
finally
FreeAndNil(aSomething1);
end;
finally
aIntfMock.Free;
end;
end;
procedure TMyTest.Test2;
var
aSut: TMyClass;
aIntfMock: TMock<IMyInterface>;
aSomething2: TSomething2;
begin
// Arrange
GlobalContainer.RegisterType<TMyClass>;
aIntfMock := TMock<IMyInterface>.Create;
try
GlobalContainer.RegisterType<IMyInterface>.DelegateTo(
function: IMyInterface
begin
Result := aIntfMock;
end)
.AsDefault;
GlobalContainer.Build; // <---- ERegistrationException here
aSomething2 := TSomething1.Create;
try
aIntfMock.Setup.WillReturn(TValue.From<TSomething2>(aSomething2)).When.GetSomething2;
aSut := GlobalContainer.Resolve<TMyClass>;
try
// Act
aSut.DoSomething;
finally
FreeAndNil(aSut);
end;
// Assert
// ...
finally
FreeAndNil(aSomething2);
end;
finally
aIntfMock.Free;
end;
end;
第一个测试方法 (Test1) 运行良好...但是在第二个测试方法 (Test2) 中,在 GlobalContainer.Build spring4d 的行中引发异常:ERegistrationException('Duplicate service name found: IMyInterface_u.IMyInterface@IMyInterface_u.IMyInterface')。
是否可以注销 aIntfMock,以便我可以为每个其他测试例程注册一个新的?
[编辑]
所以解决方案是:
TMyTest = class
private
FTestContainer: TContainer;
FIntfMock: TMock<IMyInterface>;
FSut: TMyClass;
[Setup]
procedure Setup;
[TearDown]
procedure TearDown;
[Test]
procedure Test1;
[Test]
procedure Test2;
// ...
end;
//---------------------
procedure TMyTest.Setup;
begin
FTestContainer := TContainer.Create;
FTestContainer.RegisterType<TMyClass>;
FIntfMock := TMock<IMyInterface>.Create;
FTestContainer.RegisterType<IMyInterface>.DelegateTo(
function: IMyInterface
begin
Result := FIntfMock;
end)
.AsDefault;
FTestContainer.Build;
FSut := FTestContainer.Resolve<TMyClass>;
end;
procedure TMyTest.TearDown;
begin
FreeAndNil(FSut);
FIntfMock.Free;
FreeAndNil(FTestContainer);
end;
procedure TMyTest.Test1;
var
aSomething1: TSomething1;
begin
// Arrange
aSomething1 := TSomething1.Create;
try
aIntfMock.Setup.WillReturn(TValue.From<TSomething1>(aSomething1)).When.GetSomething1;
// Act
FSut.DoSomething;
// Assert
// ...
finally
FreeAndNil(aSomething1);
end;
end;
procedure TMyTest.Test2;
begin
// ...
end;
感谢您的快速回答...
简答:否
长答案:容器不支持注销任何已注册类型的可能性。这是因为注销任何内容都可能对其他类型以及创建的实例(尤其是单例)造成级联效应。
我总是建议不要使用 GlobalContainer,而是创建自己的 TContainer 实例。然后你可以扔掉这个实例并使用一个新的实例来进行下一次测试。
您可以查看我们的单元测试,了解如何完成(Spring.Tests.Container.pas 中有 TContainerTestCase class)
除了容器之外,无论如何你都应该避免在测试中使用单例。每个单元测试都应该是独立的。一旦涉及全局状态,您可能会产生副作用。
我正在使用 spring4d、dunitx 和 delphi-mocks 编写我的第一个单元测试。 (spring4d 版本 1.1 - 12.09.2014)
在我的测试应用程序中,我自动将一个接口注入到我的被测系统 class (sut):
IMyInterface = interface [{yes, a GUID here}]
function GetSomething1: TSomething1;
function GetSomething2: TSomething2;
end;
TMyClass = class
private
[Inject]
FMyInterface: IMyInterface;
// ...
end;
现在,当我使用带有模拟的单元测试时,我使用以下(非常简单的)代码:
TMyTest = class
private
[Test]
procedure Test1;
[Test]
procedure Test2;
// ...
end;
procedure TMyTest.Test1;
var
aSut: TMyClass;
aIntfMock: TMock<IMyInterface>;
aSomething1: TSomething1;
begin
// Arrange
GlobalContainer.RegisterType<TMyClass>;
aIntfMock := TMock<IMyInterface>.Create;
try
GlobalContainer.RegisterType<IMyInterface>.DelegateTo(
function: IMyInterface
begin
Result := aIntfMock;
end)
.AsDefault;
GlobalContainer.Build;
aSomething1 := TSomething1.Create;
try
aIntfMock.Setup.WillReturn(TValue.From<TSomething1>(aSomething1)).When.GetSomething1;
aSut := GlobalContainer.Resolve<TMyClass>;
try
// Act
aSut.DoSomething;
finally
FreeAndNil(aSut);
end;
// Assert
// ...
finally
FreeAndNil(aSomething1);
end;
finally
aIntfMock.Free;
end;
end;
procedure TMyTest.Test2;
var
aSut: TMyClass;
aIntfMock: TMock<IMyInterface>;
aSomething2: TSomething2;
begin
// Arrange
GlobalContainer.RegisterType<TMyClass>;
aIntfMock := TMock<IMyInterface>.Create;
try
GlobalContainer.RegisterType<IMyInterface>.DelegateTo(
function: IMyInterface
begin
Result := aIntfMock;
end)
.AsDefault;
GlobalContainer.Build; // <---- ERegistrationException here
aSomething2 := TSomething1.Create;
try
aIntfMock.Setup.WillReturn(TValue.From<TSomething2>(aSomething2)).When.GetSomething2;
aSut := GlobalContainer.Resolve<TMyClass>;
try
// Act
aSut.DoSomething;
finally
FreeAndNil(aSut);
end;
// Assert
// ...
finally
FreeAndNil(aSomething2);
end;
finally
aIntfMock.Free;
end;
end;
第一个测试方法 (Test1) 运行良好...但是在第二个测试方法 (Test2) 中,在 GlobalContainer.Build spring4d 的行中引发异常:ERegistrationException('Duplicate service name found: IMyInterface_u.IMyInterface@IMyInterface_u.IMyInterface')。
是否可以注销 aIntfMock,以便我可以为每个其他测试例程注册一个新的?
[编辑] 所以解决方案是:
TMyTest = class
private
FTestContainer: TContainer;
FIntfMock: TMock<IMyInterface>;
FSut: TMyClass;
[Setup]
procedure Setup;
[TearDown]
procedure TearDown;
[Test]
procedure Test1;
[Test]
procedure Test2;
// ...
end;
//---------------------
procedure TMyTest.Setup;
begin
FTestContainer := TContainer.Create;
FTestContainer.RegisterType<TMyClass>;
FIntfMock := TMock<IMyInterface>.Create;
FTestContainer.RegisterType<IMyInterface>.DelegateTo(
function: IMyInterface
begin
Result := FIntfMock;
end)
.AsDefault;
FTestContainer.Build;
FSut := FTestContainer.Resolve<TMyClass>;
end;
procedure TMyTest.TearDown;
begin
FreeAndNil(FSut);
FIntfMock.Free;
FreeAndNil(FTestContainer);
end;
procedure TMyTest.Test1;
var
aSomething1: TSomething1;
begin
// Arrange
aSomething1 := TSomething1.Create;
try
aIntfMock.Setup.WillReturn(TValue.From<TSomething1>(aSomething1)).When.GetSomething1;
// Act
FSut.DoSomething;
// Assert
// ...
finally
FreeAndNil(aSomething1);
end;
end;
procedure TMyTest.Test2;
begin
// ...
end;
感谢您的快速回答...
简答:否
长答案:容器不支持注销任何已注册类型的可能性。这是因为注销任何内容都可能对其他类型以及创建的实例(尤其是单例)造成级联效应。
我总是建议不要使用 GlobalContainer,而是创建自己的 TContainer 实例。然后你可以扔掉这个实例并使用一个新的实例来进行下一次测试。
您可以查看我们的单元测试,了解如何完成(Spring.Tests.Container.pas 中有 TContainerTestCase class)
除了容器之外,无论如何你都应该避免在测试中使用单例。每个单元测试都应该是独立的。一旦涉及全局状态,您可能会产生副作用。