我一直以为xUnit不能用来测试带界面的单元,但是我错了。
看《Refactoring Improving the Design of Existing Code》中强调Testing,决定起用DUnit, 正好今天要给一个Form 增加保存字体设置的功能,遂决定从它开始。
保存和恢复复字体的代码如下,TfmXXXX是一个带有TMemeo 的Form,目标是每次打开这个Form时都能使用上次保存的字体设置,其中用到JVCL的FormStorage控件:
procedure TfmXXXX.JvFormStorageSavePlacement(Sender: TObject);
begin
JvFormStorage.WriteString(’FontName’,Memo.Font.Name );
JvFormStorage.WriteInteger(’FontSize’,Memo.Font.Size );
JvFormStorage.WriteInteger(’FontStyle’,Byte(Memo.Font.style));
JvFormStorage.WriteInteger (’FontColor’,Memo.Font.Color);
JvFormStorage.WriteInteger(’FontCharSet’,Memo.Font.Charset );
end;
procedure TfmXXXX.JvFormStorageRestorePlacement(Sender: TObject);
begin
Memo..Font.Name := JvFormStorage.ReadString(’FontName’);
Memo..Font.Size := JvFormStorage.ReadInteger(’FontSize’);
Memo..Font.Style := TFontStyles(Byte(JvFormStorage.ReadInteger(’FontStyle’)));
Memo..Font.Color := TColor(JvFormStorage.ReadInteger(’FontColor’));
Memo..Font.Charset :=TFontCharSet(JvFormStorage.ReadInteger(’FontCharSet’));
end;
测试代码如下:
procedure TTestCaseFirst.TestFontSaveRestore ;
var
Lfm : TfmXXXX;
LFont : TFont;
begin
Lfm := TfmXXXX.Create(nil);
LFont := TFont.Create ;
LFont.Assign (Lfm.Memo.Font) ;
Lfm.JvFormStorageSavePlacement(nil);
Lfm.JvFormStorageRestorePlacement(nil);
Check(LFont.Name = Lfm.Memo.Font.Name ,’Font name failure!’);
Check(LFont.Size = Lfm.Memo.Font.Size ,’Font size failure!’);
Check(LFont.Style = Lfm.Memo.Font.Style ,’Font style failure!’);
Check(LFont.Color = Lfm.Memo.Font.Color ,’Font color failure!’);
Check(LFont.Charset = Lfm.Memo.Font.Charset ,’Font charset failure!’);
end;
但是上面的测试代码不能通过,原因是fmXXXX在创建时用到了另一个Form的控件:
procedure TfmXXXX.FormCreate(Sender: TObject);
begin
JvFormStorage.AppStorage := fmMainForm.JvAppRegistryStorage;
end;
于是想到在创建Lfm之前,先创建创建fmMainForm,可是MainForm又用到了其它的Form,于是统统在Lfm之前建好,现在测试代码如下,略去相同部分:
procedure TTestCaseFirst.TestFontSaveRestore ;
var
Lfm : TfmExplodeForm;
LFont : TFont;
begin
fmMainForm := TfmMainForm.Create(nil);
fmYYYY := TfmYYYY.create(nil);
DataModule := TDataModule.create(nil);
Lfm := TfmXXXX.Create(nil);
、、、
end;
不幸的是fmMainForm在创建时启动了数据库登录界面,这个登录界面要根据fmMainForm的数据库类型来选择不同的登录方式,恕我愚钝,不知何故,在数据库登录界面中访问fmMainForm时,fmMainForm为nil,所以测试代码无法运行。
事情到了这个时候,我想,既然是要测试字体的保存和恢复,不如把上面的两个函数refactoring成两个公用函数,传递JvStorage和Font作为参数不就结了,也用不着和可视界面纠缠了。应该可行,不过我只refactoring了一个就放弃了,一方面我隐隐的觉得这样做有什么地方不大对劲(有点为测试而测试的味道),另一方面,我也懒,不相再手工refactoring 了,总觉得应该还有别的办法。
既然被测的工程一直都运行的好好的,不曾发生过这样的问题,那么不会是这些Form有问题,而应该是测试程序的用法有问题,那不如回头看看被测工程中试怎样创建这些Form的,把它们Copy过来不就行了吗?
最终把被测工程中的代码复制到测试工程中,在测试函数TestFontSaveRestore去掉新加的Form创建代码,测试代码终于可以运行,只要登录完数据库,就可以看到测试界面了:
begin
Application.Initialize;
Application.CreateForm(TfmMainForm, fmMainForm);
Application.CreateForm(TfmYYYY, fmYYYY);
Application.CreateForm(TDataModule, DataModule);
GUITestRunner.RunRegisteredTests;
end.
这样做的好处是以后要使测试别的Form时,也照样有效,要是把数据库登录对话框也给自动跳过就好了。会有办法的。今天就到这了。