gpt4 book ai didi

delphi - 如何模拟日期和现在?

转载 作者:行者123 更新时间:2023-12-03 19:02:01 25 4
gpt4 key购买 nike

我的一些代码使用Date and Now。因此,对该代码执行测试的结果取决于执行时间。那当然是不好的。
那么在测试中建议使用伪造日期和时间的推荐方式是什么?

使用界面?

最佳答案

为了使事物可测试,您需要在代码中具有或创建seams

在此特定示例中,您可能希望使用环境上下文设计模式来实现此目的。虽然起初看起来像单例,但实际上允许临时替换使用的实例或返回的数据。下面是一个示例,说明如何基于this blog post在Delphi中实现它。

我省略了线程安全性和所有其他内容,以向您提供它如何工作的基本概念。您可能还完全摆脱了TDateTimeProvider单例/类,而只是制作了自己的与模仿配合使用的Now函数。

program AmbientContextDemo;

uses
Generics.Collections,
TestFramework,
TestInsight.DUnit,
System.SysUtils;

type
TDateTimeProvider = class
strict private
class var fInstance: TDateTimeProvider;
class function GetInstance: TDateTimeProvider; static;
public
function Now: TDateTime;
class property Instance: TDateTimeProvider read GetInstance;
end;

TDateTimeProviderContext = class
strict private
var fContextNow: TDateTime;
class var contextStack: TStack<TDateTimeProviderContext>;
class function GetCurrent: TDateTimeProviderContext; static;
public
class constructor Create;
class destructor Destroy;

constructor Create(const contextNow: TDateTime);
destructor Destroy; override;

property ContextNow: TDateTime read fContextNow;
class property Current: TDateTimeProviderContext read GetCurrent;
end;

TStuff = class
// class procedure for demo purpose, no instance necessary in test
class function DoSomeDateTimeStuff_UsingNow: TDateTime;
class function DoSomeDateTimeStuff_UsingAmbientContext: TDateTime;
end;

TMyTest = class(TTestCase)
published
procedure TestIt_Fail;
procedure TestIt_Pass;
end;

{ TDateTimeProvider }

class function TDateTimeProvider.GetInstance: TDateTimeProvider;
begin
if not Assigned(fInstance) then
fInstance := TDateTimeProvider.Create;
Result := fInstance;
end;

function TDateTimeProvider.Now: TDateTime;
var
context: TDateTimeProviderContext;
begin
context := TDateTimeProviderContext.Current;
if Assigned(context) then
Result := context.ContextNow
else
Result := System.SysUtils.Now;
end;

{ TMyTest }

procedure TMyTest.TestIt_Fail;
begin
CheckEquals(EncodeDate(2018, 11, 11), TStuff.DoSomeDateTimeStuff_UsingNow);
end;

procedure TMyTest.TestIt_Pass;
var
ctx: TDateTimeProviderContext;
begin
ctx := TDateTimeProviderContext.Create(EncodeDate(2018, 11, 11));
try
CheckEquals(EncodeDate(2018, 11, 11), TStuff.DoSomeDateTimeStuff_UsingAmbientContext);
finally
ctx.Free;
end;
end;

{ TStuff }

class function TStuff.DoSomeDateTimeStuff_UsingNow: TDateTime;
begin
Result := Now; // using Now which is unmockable, only via hooking but that affects all occurences even in the RTL
end;

class function TStuff.DoSomeDateTimeStuff_UsingAmbientContext: TDateTime;
begin
Result := TDateTimeProvider.Instance.Now;
end;

{ TDateTimeProviderContext }

class constructor TDateTimeProviderContext.Create;
begin
contextStack := TStack<TDateTimeProviderContext>.Create;
end;

class destructor TDateTimeProviderContext.Destroy;
begin
contextStack.Free;
end;

constructor TDateTimeProviderContext.Create(const contextNow: TDateTime);
begin
fContextNow := contextNow;
contextStack.Push(Self);
end;

destructor TDateTimeProviderContext.Destroy;
begin
contextStack.Pop;
end;

class function TDateTimeProviderContext.GetCurrent: TDateTimeProviderContext;
begin
if contextStack.Count = 0 then
Result := nil
else
Result := contextStack.Peek;
end;

begin
RegisterTest(TMyTest.Suite);
RunRegisteredTests;
end.

关于delphi - 如何模拟日期和现在?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53261217/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com