使用测试优先方法开发用户界面

发表于:2010-5-05 16:56

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:51Testing软件测试网采编

  5、Mock Objects

  在删除操作的单元测试中,我们遇到的一个问题是,影片列表的数据应该是保存在一个文本文件或者数据库当中的,如果我们编写的测试依赖于这些实际的文件或数据库,那么我们的测试就会受制于这些外部的资源。一旦文件或者数据库里的数据发生变化,必然会波及到我们的测试代码,从而产生错误的测试信息。前面的MovieListEditor中我们没有加入一些初始化的数据,在测试删除操作时会遇到一些问题 。

  这里,我们引入Mock Objects。Mock Objects用来模拟外部复杂的资源(如数据库,网络连接等),使UI可以测试那些依赖于这些复杂外界资源的模块。例如在测试一个跟数据库有关系的模块时,我们并不一定要建立一个真实的数据库连接,而只需建立一个Mock Objects就可以了。测试所需的数据都存在于这个Mock Objects。可以说,Mock Objects为我们提供了一个轻量级的、可控制的、高效的模型。

  在本例中,影片的增加、删除都会跟文件或数据库操作发生关系。这时我们就可以利用Mock Objects来隔离测试代码与文件或数据库。使用Mock Objects一般有以下几个步骤:

  a)、定义一个外部资源的接口.(这个接口一般是可以在重构过程中提炼出来的)。

  b)、定义一个Mock Objects,从外部资源的接口继承下来,实现外部资源的接口。

  c)、创建一个Mock Objects,并设置它的内部期望值。

  d)、把创建的这个Mock Objects传递给需要测试的模块进行操作。

  e)、操作完毕后将Mock Objects内部的状态与期待状态比较。 现在我们就根据这个步骤来实现本例子中的Mock Objects.通过对前面的代码进行重构,我们可以提炼出一个接口MovieListEditor:
 

  class AFX_EXT_CLASS MovieListEditor
{
public:
    MovieListEditor();
    virtual ~MovieListEditor();
public:
    virtual CStringArray* GetMovies()=0;
    virtual void Add(CString strMovie)=0;
    virtual void Delete(int nIndex)=0;
};

  请注意它和前面我们定义的MovieListEditor的不同。接下来,我们应该定义一个Mock Objects,当然它是从MovieListEditor继承下来的:
 

 class mockEditor : public MovieListEditor
{
public:
     mockEditor();
     virtual ~mockEditor();
public:
     virtual CStringArray* GetMovies(){return &m_arMovieList;};
     virtual void Add(CString strMovie){m_arMovieList.Add(strMovie);};
     virtual void Delete(int nIndex){m_arMovieList.RemoveAt(nIndex);};
private:
     CStringArray m_arMovieList;
};

    然后给这个Mock Objects设置初识值,我们选择在它的构造函数里进行。
 

 mockEditor::mockEditor()
{
     m_arMovieList.Add("Star Wars");
     m_arMovieList.Add("Star Trek");
     m_arMovieList.Add("Stargate");
}

  我们添加了三个影片用于测试。接着,应该把这个MockObjects的一个实例传递给需要测试的模块。这里就是我们要测试的UI(MovieListWindow)。
 

 m_pEditor = new mockEditor();
   MovieListWindow *pWindow = new MovieListWindow(m_pEditor);

    最后我们来看看经过修改后的新的测试添加影片的方法:
 

 void TestOperation::testAdd()
{
     //拷贝一份movie list
      CStringArray MovieNamesWithAddition;
     for(int n=0; n<m_MovieNames.GetSize(); n  )
     {
        MovieNamesWithAddition.Add(m_MovieNames.GetAt(n));
     }
     MovieNamesWithAddition.Add(LOST_IN_SPACE);
     //生成窗口
     MovieListWindow *pWindow = new MovieListWindow(m_pEditor);
     pWindow->Init();
     //填写新的影片的名称
     CEdit* pEdit = pWindow->GetMovieField();
     pEdit->SetWindowText(LOST_IN_SPACE);
     //点击add btn
     CButton* pBtn = pWindow->GetAddButton();
     ::SendMessage(pBtn->m_hWnd, BM_CLICK, 0, 0);
     //检查列表控件中是否已加入新的影片
     CListBox* pListBox = pWindow->GetMovieListBox();
     CPPUNIT_ASSERT_EQUAL(MovieNamesWithAddition.GetSize(), pListBox->GetCount());
     //将Mock Objects的内部数据和期望值进行比较
     CPPUNIT_ASSERT_EQUAL(MovieNamesWithAddition.GetSize(),
     m_pEditor->GetMovies()->GetSize());
     //检查列表控件中影片名是否正确
     CString strNewMovieName;
     pListBox->GetText(pListBox->GetCount()-1, strNewMovieName);
     CPPUNIT_ASSERT_EQUAL(LOST_IN_SPACE, strNewMovieName);
     //将Mock Objects的内部数据和期望值进行比较
     int nIndex = m_pEditor->GetMovies()->GetSize();
     CPPUNIT_ASSERT_EQUAL(LOST_IN_SPACE, m_pEditor->GetMovies()->GetAt(nIndex-1));
     //销毁窗口
     pWindow->DestroyWindow();
     delete pWindow;
     pWindow = NULL;
}

  请注意,这里测试的数据都是mockEditor里的,而且在UI进行添加操作后,还将mockEditor内部的状态与期待状态做了比较。
 

 CPPUNIT_ASSERT_EQUAL(MovieNamesWithAddition.GetSize(), m_pEditor->GetMovies()->GetSize());
   CPPUNIT_ASSERT_EQUAL(LOST_IN_SPACE, m_pEditor->GetMovies()->GetAt(nIndex-1));

  其他删除操作的测试跟添加类似,在此不做详述。至此,我们就完成了这个GUI应用程序的开发。

  6、源码说明

  本文附带的代码包括三个Project,分别是Movie、 GuiTestFirst、AppMovieList.Movie是产品代码.GuiTestFirst是测试代码。AppMovieList是使用 Movie输出的产品代码而写的应用程序,它从MovieListEditor继承出一个新的影片管理类 MyEditor。它主要是演示如何使用我们提炼出来的MovieListEditor接口。例如你可以实现 CXmlMovieListEditor,CAccessMovieListEditor等等。进入GuiTestFirst打开所有这些工程。

  7、总结

    a)、对GUI应用实施测试优先开发方法,这在测试驱动开发中并不是必须的,可根据开发的实际情况来选择。
    b)、我们通过引入Mock Objects,我们使测试代码和外部复杂的资源隔离开来,同时也使我们能够从中既有代码中提炼出清晰的接口,使代码整洁可用。

    8、参考资料

    《测试驱动开发实用指南(影印版)》David Astels

    《测试驱动开发(中文版)》Kent Beck

    《Endo-Testing: Unit Testing with Mock Objects》Tim Mackinnon, Steve Freeman, Philip Craig

33/3<123
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号