2013-10-25 186 views
0

这比起其他任何东西都更像是一个junit逻辑问题。Junit:分离测试用例

我的方案是如下:

我有一个从Web服务使用数据,并从客户端(应用程序正在运行)机上的服务,将数据保存一个独立的Java应用程序。

此数据以XML格式保存,然后由另一个应用程序读取,以在厚客户端UI上呈现该内容。

流量低于图中所描绘的:

enter image description here

我希望写该流动单元测试,但我不理解如何单元测试我有逻辑用于消耗web服务,然后验证客户机器上保存的内容是否正确。

另一个难题是如何验证(单元测试)使用保存在客户机上的XML呈现UI上的内容。

我知道每个junit都必须尽可能小,并且应该独立测试底层功能。

该应用程序将托管在像Hudson这样的持续集成环境中,并且可能不会提供应用程序向该机器写入任何内容的权限。这使事情进一步复杂化。

任何帮助,将不胜感激。

在上述场景中,为了简单起见,我将独立应用程序和胖客户端分开显示,但实质上它们可以是一个应用程序。

读取要显示的XML数据的胖客户端以javafx编码。

回答

3

你没有指定什么将用作UI?这会是一个GUI应用程序或网络? 这对一般方法有一些影响,但只是提供一些提示,我会分享我的经验。我使用swing做了很多gui应用程序,这将是我的基准。

所以趋势是让你的GUI尽可能的瘦,并把逻辑,只负责显示组件。为了实现这一点,您可以使用像Presentation Model(http://martinfowler.com/eaaDev/PresentationModel.html)或Passive View(http://martinfowler.com/eaaDev/PassiveScreen.html)这样的众所周知的设计模式。

然后您开始测试您的业务逻辑。一般的指导原则是:

  • 您不使用外部资源(文件,数据库等),而是用替换它们的Fakes或Mocks为您的测试提供一些固定的输入。
  • 您只测试类的行为不依赖的行为
  • 尽量避免复杂的输入
  • 使用中提到的模式,你可以嘲笑你的视图层和只测试是否看某些方法,其中在synchrronization层称为。

我希望我能帮上忙。如果不让我知道是否有点模糊。如果你能举一个例子,你会如何解决这个问题,以及你对于你的方法有什么担忧,这也是一件好事。

@举例

我没有使用JavaFX经验,所以我会尽量表现出我会怎么做它摇摆。 这个例子假定你知道什么是模拟,它们是什么。

首先让我们弄清楚瘦客户机中最重要的功能是什么。我会去做那样的事情。用户打开xml文件,应用以某种形式显示它。 (形式不重要,它可能是树,它可能是一张桌子或一个网格无论什么,因为它是视图,我现在不在乎)

基本方案将是用户选择一个文件,应用程序打开该文件并解析它,然后显示结果。我们称之为“Open Results”。

初试:

class OpenResultsShould{ 
    @Test 
    public void loadResults() { 
     Data fake = mock (Data.class); 
     ViewInterface view = mock(ViewInterface.class); // mocking view 
     when(view.getFilename()).thenReturn("file.xml"); // we specify that when getFileName() method of view mock will be called "file.xml" string will be returned. 

     ApplicationModelInterface appModel = mock(ApplicationModelInterface.class); // mocking app model 
     when(appModel.getDataForView()).thenReturn(fake); 

    OpenResultsAction openResults = new OpenResultsAction(view, appModel); 

     openResults.actionPerformed(new ActionEvent()); 

     verify(view).getFileName();   // checks that view.getFileName was called within actionPerdormed() 
     verify(appModel).load("file.xml"); // check that appModel.load() with file.xml as parameter was called within actionPerformed() 
     verify(appModel).getDataForView(); // similar to above 
     verify(view).loadDataFromModel(fake); // finally I check if loadDataFromModel on view was called. 
    } 
} 

这个测试的目的是检查是否OpenResultsAction将做的工作。这里我们没有测试解析的内容以及gui是否有正确的数据。我们测试某些对象的某些方法是否被调用。此测试还指定了操作类,视图和applicationModel之间的契约。这是通过接口完成的。所以你稍后可以提供具体的实现,这将在下一步中进行测试。 然后我会提供实现,我将跳过这个例子尽可能短。

接下来是什么。由于gui不会被测试,我会去ApplicationModel测试。在第一次测试中,我们指定applicationModelInterface应该有方法加载(String filename);我们将测试它是否具体实现。

class ApplicationModelShould{ 
    @Test 
    public void loadModelFromFile() { 
     XMLDocument xml = new XMLDocumentFake(); 
     XMLFileLoader xFileLoader = mock(XMLFileLoader.class); 
     when(xFileLoader.load("file.xml").thenReturn(xml); 
     ApplicationModelInterface appModel = new ConcreteApplicationModel(new FileLoaderFake()); 

     appModel.load("plik.xml"); // it should call xFileLoader and then parse returned xml document. 
     doReturn(xml).when(xFileLoader).load("plik.xml"); // verifies if xFileLoader returned xml when appModel.load called it's load method. 
     Data expectedResult = populateExpectedResults(); 
     assertEquals(appModel.getDataForView().equals(expectedResult)); 
    } 
} 

什么是XMLDocument?它存储xml文件的内容。它可以表示为文件行的向量。我们的AppModelLoader会将其解析为对象。 XFileLoader是另一个允许我在单元测试中摆脱文件操作的层。在这里它被嘲笑,但在真正的应用程序中,它应该替换为将读入xml文件并返回XMLDocument的somethind。数据是一个将用于存储分析数据的类。如果XML的内容是“<人> <名>汤姆< /名称> <年龄 /年龄> < /人>然后数据会看起来像:

class Data{ 
    private Person person; 
    Data(Person person){ this.person = person; } 
    ... 
}; 

class Person{ 
    private String name; 
    private int age; 
    .... setters, getters and constructors 
} 

这基本上是它当然需要更多的测试,例如如果view.getFileName()将返回OpenResultsAction中的空字符串(用户在JFileChooser上点击取消),那么我需要验证是否没有其他东西被调用。如果我将所有的类都测试过,那么我会写GUI部分并结合它。

让我知道这是否合理。

+0

感谢您的好评[Luke](http://stackoverflow.com/users/2862100/luke)。我使用有关胖客户端(javafx)的信息编辑了我的问题。有没有办法为javafx应用程序伪造或模拟内容?或者就此而言,这将如何解决摆动应用程序? – Aspirant

+1

我用一个例子编辑了我的答案。它在@Example之后开始 – Luke