Create code for a simple math library and test it. Methods include Add, divide, subject and multiply
Refactor code that is part of your interface but should be in separate classes.

We start out (TFormWorst) with code that is very repetitious. Note that the first four lines in each procedure is identical.
procedure TFormWorst.ButtonDaysPassedClick(Sender: TObject); begin FDay := StrToInt(EditDay.Text); FMonth := StrToInt(EditMonth.Text); FYear := StrToInt(EditYear.Text); FDateTime := EncodeDateTime(FYear, FMonth, FDay, 0, 0, 0, 0); EditDaysPassed.Text := IntToStr(DaysBetween(Now, FDateTime)); end; procedure TFormWorst.ButtonHoursPassedClick(Sender: TObject); begin FDay := StrToInt(EditDay.Text); FMonth := StrToInt(EditMonth.Text); FYear := StrToInt(EditYear.Text); FDateTime := EncodeDateTime(FYear, FMonth, FDay, 0, 0, 0, 0); EditHours.Text := IntToStr(DaysBetween(Now, FDateTime) * 24); end;
In the next step (TFormBetter), we factor out the code that is overly repetitious into its own method:
procedure TFormBetter.GetData(); begin FDay := StrToInt(EditDay.Text); FMonth := StrToInt(EditMonth.Text); FYear := StrToInt(EditYear.Text); FDateTime := EncodeDateTime(FYear, FMonth, FDay, 0, 0, 0, 0); end;
Then we create two methods for handling the getting days and hours passed chores:
function TFormBetter.GetDaysPassed: Integer; begin Result := DaysBetween(Now, FDateTime); end; function TFormBetter.GetHoursPassed: Integer; begin Result := GetDaysPassed * 24; end;
Though we have added to the total amount of code we have written we can see the advantage we have created when we look at the button response methods. Both of them are now much simpler, and much easier to understand:
procedure TFormBetter.ButtonDaysPassedClick(Sender: TObject); begin GetData(); EditDaysPassed.Text := IntToStr(GetDaysPassed()); end; procedure TFormBetter.ButtonHoursPassedClick(Sender: TObject); begin GetData(); EditHours.Text := IntToStr(GetHoursPassed()); end;
The final refactoring that we must complete will enable us to place all this code in a separate class.
unit WorkObject;
interface
uses
SysUtils, DateUtils;
type
{ Should be a private class
A Simple date object, which encapsulates FDateTime }
TWorkDate = class(TObject)
private
FDateTime: TDateTime;
FYear: Integer;
FMonth: Integer;
FDay: Integer;
public
constructor Create(const AMonth: Integer; const ADay: Integer; const AYear: Integer);
procedure Init(const AMonth: Integer; const ADay: Integer; const AYear: Integer);
property DateTime: TDateTime read FDateTime write FDateTime;
property Day: Integer read FDay write FDay;
property Month: Integer read FMonth write FMonth;
property Year: Integer read FYear write FYear;
end;
{ A class that can perform certain operations on a TWorkDate Object.
GetDayspassed Since a given date
GetHousePassed since a given date.
Get the current data }
TWorkObject = class(TObject)
private
FWorkDate: TWorkDate;
public
constructor Create(); overload;
constructor Create(const AMonth: Integer; const ADay: Integer; const AYear: Integer); overload;
constructor Create(AWorkDate: TWorkDate); overload;
procedure Init(); overload;
procedure Init(const AMonth: Integer; const ADay: Integer; const AYear: Integer); overload;
function GetDay: Integer;
function GetDaysPassed: Integer;
function GetHoursPassed: Integer;
function GetMonth(): Integer;
function GetTodaysDate(): String;
function GetYear(): Integer;
end;
implementation
{ TWorkDate }
{ Constructor to use to initialize the dates }
constructor TWorkDate.Create(const AMonth, ADay, AYear: Integer);
begin
Init(AMonth, ADay, AYear);
end;
procedure TWorkDate.Init(const AMonth, ADay, AYear: Integer);
begin
FYear := AYear;
FMonth := AMonth;
FDay := ADay;
end;
{ TWorkObject }
constructor TWorkObject.Create;
begin
Init(0, 0, 0);
end;
constructor TWorkObject.Create(const AMonth, ADay, AYear: Integer);
begin
Init(AMonth, ADay, AYear);
end;
constructor TWorkObject.Create(AWorkDate: TWorkDate);
begin
FWorkDate := AWorkDate;
Init();
end;
function TWorkObject.GetDay: Integer;
begin
Result := FWorkDate.Day;
end;
function TWorkObject.GetDaysPassed: Integer;
begin
Result := DaysBetween(Now, FWorkDate.DateTime)
end;
function TWorkObject.GetHoursPassed: Integer;
begin
Result := GetDaysPassed * 24;
end;
function TWorkObject.GetMonth: Integer;
begin
Result := FWorkDate.Month;
end;
function TWorkObject.GetTodaysDate: String;
begin
Result := DateTimeToStr(Now);
end;
function TWorkObject.GetYear(): Integer;
begin
Result := FWorkDate.Year;
end;
procedure TWorkObject.Init(const AMonth, ADay, AYear: Integer);
begin
FWorkDate := TWorkDate.Create(AMonth, ADay, AYear);
Init();
end;
procedure TWorkObject.Init();
begin
FWorkDate.FDateTime := EncodeDateTime(FWorkDate.Year, FWorkDate.Month, FWorkDate.Day, 0, 0, 0, 0);
end;
end.
Here is test code confirm that the class works okay.
unit WorkObjectTests;
interface
uses
SysUtils,
WorkObject,
TestFrameWork;
const
MAX_DATES = 4;
type
TWorkObjectTests = class(TTestCase)
private
FWorkDates: array [0..MAX_DATES] of TWorkDate;
FWorkObjects: array[0..MAX_DATES] of TWorkObject;
protected
procedure SetUp; override;
procedure TearDown; override;
published
// Test methods
procedure TestGetDay;
procedure TestGetMonth;
procedure TestGetTodaysDate;
procedure TestGetYear;
end;
{ TInitFixture = class
constructor Create();
function Init: TWorkObject(WorkObjectTests: TWorkObjectTests);
end; }
implementation
{ TWorkObjectTests }
procedure TWorkObjectTests.SetUp;
begin
inherited;
FWorkDates[0] := TWorkDate.Create(6, 7, 1999);
FWorkObjects[0] := TWorkObject.Create(FWorkDates[0]);
FWorkDates[1] := TWorkDate.Create(7, 8, 1900);
FWorkObjects[1] := TWorkObject.Create(FWorkDates[1]);
FWorkDates[2] := TWorkDate.Create(8, 9, 1500);
FWorkObjects[2] := TWorkObject.Create(FWorkDates[2]);
FWorkDates[3] := TWorkDate.Create(9, 10, 500);
FWorkObjects[3] := TWorkObject.Create(FWorkDates[3]);
FWorkDates[4] := TWorkDate.Create(10, 11, 50);
FWorkObjects[4] := TWorkObject.Create(FWorkDates[4]);
end;
procedure TWorkObjectTests.TearDown;
var
i: Integer;
begin
inherited;
for i := 0 to MAX_DATES do begin
FreeAndNil(FWorkObjects[i]);
FreeAndNil(FWorkDates[i]);
end;
end;
procedure TWorkObjectTests.TestGetDay;
var
Day, i: Integer;
begin
for i := 0 to MAX_DATES do begin
Day := FWorkObjects[i].GetDay;
CheckEquals(FWorkDates[i].Day, Day);
end;
end;
procedure TWorkObjectTests.TestGetMonth;
var
Month, i: Integer;
begin
for i := 0 to MAX_DATES do begin
Month := FWorkObjects[i].GetMonth;
CheckEquals(FWorkDates[i].Month, Month);
end;
end;
procedure TWorkObjectTests.TestGetTodaysDate;
var
Date: String;
begin
Date := FWorkObjects[0].GetTodaysDate();
Check(Length(Date) <> 0);
end;
procedure TWorkObjectTests.TestGetYear;
var
Year, i: Integer;
begin
for i := 0 to MAX_DATES do begin
Year := FWorkObjects[i].GetYear();
CheckEquals(FWorkDates[i].Year, Year);
end;
end;
initialization
TestFramework.RegisterTest('WorkObjectTests Suite',
TWorkObjectTests.Suite);
end.
Use unit tests while constructing a biderectional list object