Delphi Mocks with class helper - unit-testing

I really like Delphi Mocks, but it seems to have a problem with class helpers. I have a class helper that extends TRESTResponse and want to test the functions I added. Unfortunately, this does not work. I have created the following simple reproduction:
MyClass = class
function MyFunc1: Integer; virtual;
end;
MyClassHelper = class helper for MyClass
function MyFunc2: Integer; virtual;
end;
var
LMock: TMock<MyClass>;
begin
LMock := TMock<MyClass>.Create;
LMock.Setup.WillReturn(2).When.MyFunc1;
LMock.Setup.WillReturn(2).When.MyFunc2;
Assert(LMock.Instance.MyFunc1 <> 1);
Assert(LMock.Instance.MyFunc2 <> 1);
end;
function MyClass.MyFunc1: Integer;
begin
Result := 1;
end;
function MyClassHelper.MyFunc2: Integer;
begin
Result := 1;
end;
Mocking MyFunc1 works as expected, but MyFunc2 cannot be mocked. The second LMock.Setup.WillReturn-line raises an exception [MyClass] already defines Will Return When for method [MyFunc1]. If you remove the mocking setup for MyFunc1 then no exception is raised, but MyFunc2 is not mocked.
Any suggestions how to solve this? Or is it not possible to mock class helpers with Delphi Mocks?

Related

dataProvider in DUnit Delphi?

How to provide data for Unit Tests in Delphi DUnit) ? For example, in PHP, you can do something like this:
public function URLProvider() {
return [
["https://helloacm.com"],
["https://codingforspeed.com"]
];
}
/**
* #dataProvider URLProvider
*/
public function test_url($url) {
$data = file_get_contents("$this->API?url=$url");
$result = json_decode($data, true);
$this->assertEquals(true, $result['result']);
$this->assertEquals(200, $result['code']);
}
With Spring4D DUnit extensions you can write something like that (look into the release/1.2 branch in the Tests\Source folder for the unit Spring.Testing).
program Tests;
uses
Spring.Testing,
TestInsight.DUnit;
type
TUrlTests = class(TTestCase)
public
class function UrlProvider: TArray<string>; static;
published
[TestCaseSource('UrlProvider')]
procedure TestUrl(const url: string);
end;
{ TUrlTests }
procedure TUrlTests.TestUrl(const url: string);
begin
// do whatever
end;
class function TUrlTests.UrlProvider: TArray<string>;
begin
Result := ['https://helloacm.com', 'https://codingforspeed.com'];
end;
begin
TUrlTests.Register;
RunRegisteredTests;
end.
You can either pass the name to the method within the same Testcase class or specify another class - the method itself must be a public static class function. The extension then will create different test cases for each parameter being passed. You can check the Unittests of Spring4D for other use cases.
In DUnit every single test case has to be a procedure without parameters. So there can't exist a mechanism for injecting arguments via custom attributes to test methods like you are doing it PHPUnit.
You should take a look at DUnitX instead where you can define tests like this:
[TestCase('https://helloacm.com')]
[TestCase('https://codingforspeed.com']
procedure TestUrl(const Url: String);

Can I pass type parameters to a testcase in DUnitx?

I'm writing testcases for my FastCode project.
I've written a generic tester like so:
TTest<T> = record
private
class var Def: System.Generics.Defaults.IComparer<T>;
class var F: FastDefaults.TComparison<T>;
strict private
class function Slow(const Left, Right: T): integer; static;
class function Fast(const Left, Right: T): integer; static;
class constructor Init;
public
class procedure Test(const Left, Right: T); static;
end;
A typical test case looks like:
[Test]
[TestCase('Single', '100.0,100.0')]
...many more testcases...
procedure TestSingle(const L,R: Single);
[Test]
[TestCase('Double', '100.0,100.0')]
...many more testcases... (identical to the one above).
procedure TestDouble(const L,R: double);
The testing code is typically as follows (repeated for every single type):
procedure TestDefault.TestSingle(const L, R: Single);
begin
TTest<Single>.Test(L,R);
end;
What I would like to do:
[Test]
[TestTypes('single,double,extended')]
[TestCase('description', '100.0,100.0')]
...many more test cases....
procedure Test<TC>(L,R: TC);
And have the test run for the types stated, so that I don't have to write so much boilerplate.
Can something like this be done in DUnitX?
Try to make your test class generic and register your test class with every single concrete type you want to test.
[TestFixture]
TMyTestObject<T> = class(TObject)
public
// Sample Methods
// Simple single Test
[Test]
procedure Test1;
// Test with TestCase Atribute to supply parameters.
[Test]
[TestCase('TestA','1,2')]
[TestCase('TestB','3,4')]
procedure Test2(const AValue1 : T; const AValue2 : T);
end;
//...
initialization
TDUnitX.RegisterTestFixture(TMyTestObject<integer>);
TDUnitX.RegisterTestFixture(TMyTestObject<double>);

Need help converting Graphics32 Delphi sample to C++

USING BDS2006:
I'm trying to convert the Graphics32 Resampler_ex example in C++, but i can't even understand what happens in some codes, or how to rewrite that code in C++.
In that sample there's a combobox to choose what resampler to use:
This is the Deplhi code in his OnChange event:
procedure TfmResamplersExample.KernelClassNamesListClick(Sender: TObject);
var
Index: Integer;
begin
Index := KernelClassNamesList.ItemIndex;
if Src.Resampler is TKernelResampler then
with TKernelResampler(Src.Resampler) do
begin
Kernel := TCustomKernelClass(KernelList[Index]).Create;
LbParameter.Visible := (Kernel is TAlbrechtKernel) or
{$IFDEF Ex}
(Kernel is TGaussianKernel) or
(Kernel is TKaiserBesselKernel) or
(Kernel is TNutallKernel) or
(Kernel is TBurgessKernel) or
(Kernel is TBlackmanHarrisKernel) or
(Kernel is TLawreyKernel) or
{$ENDIF}
(Kernel is TSinshKernel);
gbParameter.Visible := LbParameter.Visible;
SetKernelParameter(Kernel);
CurveImage.Repaint;
end;
end;
where:
{ TClassList }
{ This is a class that maintains a list of classes. }
TClassList = class(TList)
protected
function GetItems(Index: Integer): TClass;
procedure SetItems(Index: Integer; AClass: TClass);
public
function Add(AClass: TClass): Integer;
function Extract(Item: TClass): TClass;
function Remove(AClass: TClass): Integer;
function IndexOf(AClass: TClass): Integer;
function First: TClass;
function Last: TClass;
function Find(AClassName: string): TClass;
procedure GetClassNames(Strings: TStrings);
procedure Insert(Index: Integer; AClass: TClass);
property Items[Index: Integer]: TClass read GetItems write SetItems; default;
end;
ResamplerList: TClassList;
My problems are on this line
Kernel := TCustomKernelClass(KernelList[Index]).Create;
How can i convert this line in C++?
EDIT AFTER THE COMMENTS AND THE ANWERS:
Ok, seems beyond my undertanding. For my purposes, it will suffice to be able to replicate what this code do without too much hassle.
Could it be possible to instantiate the right class just using a switch based on the itemindex?
These are the 4 classes i should instantiate:
class DELPHICLASS TNearestResampler;
class PASCALIMPLEMENTATION TNearestResampler : public Gr32::TCustomResampler
{
typedef Gr32::TCustomResampler inherited;
[...]
}
class DELPHICLASS TLinearResampler;
class PASCALIMPLEMENTATION TLinearResampler : public Gr32::TCustomResampler
{
typedef Gr32::TCustomResampler inherited;
[...]
};
class DELPHICLASS TDraftResampler;
class PASCALIMPLEMENTATION TDraftResampler : public TLinearResampler
{
typedef TLinearResampler inherited;
[...]
};
class DELPHICLASS TKernelResampler;
class PASCALIMPLEMENTATION TKernelResampler : public Gr32::TCustomResampler
{
typedef Gr32::TCustomResampler inherited;
[...]
};
I don't ever get how could i assign one of them to "Kernel"....
The Delphi code relies on Delphi virtual constructors. This functionality does not exist in C++.
If you wanted to translate the code literally then you'd need to find a way to instantiate the class by calling the virtual Delphi constructor. You cannot do that in C++ so you'd need some Delphi code to glue it all together. Remy's answer here shows how to use __classid() to obtain a Delphi metaclass. You'd then need to pass that metaclass to a Delphi function to perform the instantiation.
Frankly I would view that as being a rather convoluted solution to the problem. Instead I think I'd replace the class list with a function list. The functions in the list would have the task of instantiating a new instance of a kernel. So instead of adding a class to the list, you add a function that creates a new instance of the class. In fact you might want a map between name and function, it all depends on your needs.
From what I remember from Delphi programming, this will actually instantiate the same type of class, which currently is kept in KernelList[index] and then cast it back to TCustomKernelClass. AFAIK there is no such mechanism in C++, but you can solve it by introducing virtual CreateInstance method:
class TCustomKernelClass
{
public:
virtual TCustomKernelClass * CreateInstance() = 0;
}
class TDerivedKernelClass
{
public:
TCustomKernelClass * CreateInstance()
{
return new TDerivedKernelClass();
}
}
You'll have to introduce some changes in the classes though. I doubt it can be solved directly in C++.
Edit: In response to comments
Ok, I see now, there are class definitions kept in that list. Since RTTI in C++ is not as extensive as in Delphi, I'd change the code to (written from memory, may not compile):
std::vector<std::function<TBaseKernelClass(void)>> KernelList;
KernelList.push_back([]() { return new TDerivedKernelClass(); });
// (...)
Kernel = KernelList[index]();

Lazarus/Pascal: Problems with dynamic Toggleboxes

We have two classes which are important:
uSitz, uGUI.
unit uSitz;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, stdctrls;
type txyTogglebox=class(TTogglebox)
private
x:integer;
y:integer;
public
constructor create(xi,yi:integer;TheOwner:tobject);
end;
implementation
constructor txytogglebox.create(xi,yi:integer;TheOwner:tobject);
begin
x:=xi;
y:=yi;
end;
end.
It inherits the class TToggleBox!
So then we have the uGUI:
unit uGUI;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, usaal, usitz, stdctrls;
type
{ TForm1 }
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
i,j:integer;
saal:tsaal;
xytoggles: array of array of txytogglebox;
implementation
{$R *.lfm}
{ TForm1 }
procedure toggleboxclick(Sender:TObject);
begin
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
setlength(xytoggles, 10, 10);
saal.create(10,10);
for i:=0 to 10 do
begin
for j:=0 to 10 do
begin
xytoggles[i,j].create(i,j,form1);
xytoggles[i,j].parent:=form1;
xytoggles[i,j].Visible:=true;
xytoggles[i,j].top:=i*10;
xytoggles[i,j].left:=j*10;
xytoggles[i,j].width:=10;
xytoggles[i,j].height:=10;
xytoggles[i,j].onclick:=#toggleboxclick;
end;
end;
end;
end.
So the compiler says that we have an error #: ugui.pas(64,29) Error: Incompatible types: got "<address of procedure(TObject);Register>" expected "<procedure variable type of procedure(TObject) of object;Register> ".
If i change the procedure "toggleboxclick" to TForm1.toggleboxclick i will get a new error: nullpointer-exception (sigserv or something like this) # "xytoggles[i,j].parent:=form1;". How i can solve this problem.
At last: Sry for my english ;)
If i change the procedure "toggleboxclick" to TForm1.toggleboxclick
That is the correct way to do it
i will get a new error: nullpointer-exception (sigserv or something like this) # "xytoggles[i,j].parent:=form1;". How i can solve this problem.
You cannot use object.create. You need to use object := TClass.create. I.e.: In your case:
saal := tsaal.create(10, 10);
xytoggles[i,j] := txyTogglebox.create(i,j,form1);
It is also bad style to have global variables like i,j,saal, xytoggles. Better make i,j local variables; and saal, xytoggles class fields

Delphi typcast tlist items C++ approach

Hi I have one question regarding some type casting approaches. I am translating some Delphi files to C++. I have delphi declaration of class which is derived from TList and it's a base class for other derived classes.
type TBaseItem = class (TObject)
public
procedure SomeProcedure; virtual; abstract;
end;
Type TBaseClass = class(TList)
private
function GetItem(Index: Integer): TBaseItem;
procedure SetItem(Value: TBaseItem; Index: Integer);
public
property Items[Index: Integer]: TBaseItem read GetItem write SetItem;
end;
function TBaseClass.GetItem(Index: Integer): TBaseItem;
begin
Result := TBaseItem(inherited Items[Index]);
end;
procedure TBaseClass.SetItem(Value: TBaseItem; Index: Integer);
begin
inherited Items[Index] := Value;
end;
This are two base classe TBaseItem and TBaseClass. So here are declared new classes TchildItem which is derived from TBaseItem and TChildClass which is derived from TBaseClass. TChildItem is overriding method SomeMethod and what is more important is that TChildtClass is overriding property Items in a way that now we are returning TParentItem items insted of TBaseItem.
type TChildItem = class (TBaseItem)
public
procedure SomeProcedure; override;
end;
type TChildClass = class(TBaseClass)
private
function GetItem(Index: Integer): TChildItem;
procedure SetItem(Value: TChildItem; Index: Integer);
public
property Items[Index: Integer]: TChildItemread GetItem write SetItem;
end;
function TChildClass .GetItem(Index: Integer): TChildItem;
begin
Result := TChildItem(inherited Items[Index]);
end;
procedure TChildClass.SetItem(Value: TChildItem; Index: Integer);
begin
inherited Items[Index] := Value;
end;
With this example I wanted to show how easy can be done deriving classes and overriding properties. Getting proper type of item out of a list is simply done by calling parents (base) property Item and typecast it to proper type. This is delphi apporach.
I wonder how can I translate this part of code to C++. Currently I declared a new base class which is not derived from any class and it has public var Items which is
class TBaseItem{
virtual void SomeMethod();
}
class TBaseClass {
public:
vector<TBaseItem> Items;
};
class TChildItem : public TBaseItem{
}
class TChildClass : public TBaseClass {
};
and then use
return (TChildItem) Items[Idx]
That means I would like to access parent's (TBaseClass) public variables such as that vector Items and typecast it to proper type... My first impression is that I might be going into wrong direction with that Delphi approach.
What do you suggest? How should I go with that?
THANK YOU VERY MUCH!
The Delphi code is old and pre-dates generics, the Delphi analogue to C++ templates. In modern Delphi code those list classes would simply not exist. Instead one would use TList<TBaseItem> and TList<TChildItem>.
In C++ code you would simply use vector<TBaseItem*> and vector<TChildItem*>. There is simply no point in your C++ translation to implement TBaseClass and TChildClass.
I would also correct your terminology. Delphi properties cannot be overriden. The new property in TChildClass is just that, a new property.