0

这更像是一个junit逻辑问题。

我的情况如下:

我有一个独立的 Java 应用程序,它使用来自 Web 服务的数据并将来自该服务的数据保存在客户端(运行应用程序的地方)机器上。

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

流程如下图所示:

在此处输入图像描述

我希望为此流程编写单元测试,但我不明白如何对使用 Web 服务的逻辑进行单元测试,然后验证保存在客户端机器上的内容是否正确。

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

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

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

任何帮助,将不胜感激。

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

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

4

1 回答 1

3

您没有指定将用作 UI 的内容?这将是一个 GUI 应用程序还是一个 Web 应用程序?这对一般方法有一些影响,但只是为了给出一些提示,我将分享我的经验。我使用 swing 做了很多 gui 应用程序,这将是我的基线。

所以趋势是让你的 GUI 尽可能的薄,并放在那里只负责显示组件的逻辑。为了实现这一点,您可以使用众所周知的设计模式,如演示模型 ( http://martinfowler.com/eaaDev/PresentationModel.html ) 或被动视图 ( http://martinfowler.com/eaaDev/PassiveScreen.html )

然后你开始测试你的业务逻辑。一般指导方针是:

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

我希望我有所帮助。如果不让我知道是否有些模糊。如果你能举例说明你想如何解决这个问题以及你对你的方法有什么顾虑,那也很好。

@例子

我没有使用 JavaFx 的经验,所以我将尝试展示如何在 Swing 中进行操作。此示例假设您知道什么是模拟以及它们的用途。

首先让我们弄清楚瘦客户端中最重要的功能是什么。我会去做类似的事情。用户打开 xml 文件,应用程序以某种形式显示它。(表格并不重要,它可以是树,也可以是表格或网格。因为它是视图,所以我现在不在乎)

基本场景是用户选择一个文件,应用程序打开该文件并解析它,然后显示结果。让我们将此场景称为“开放结果”。

第一次测试:

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 是否有正确的数据。我们测试是否调用了某些对象的某些方法。该测试还指定了动作类、视图和应用程序模型之间的契约。这是通过接口完成的。因此,您可以稍后提供将在下一步中测试的具体实现。然后我将提供实现,我将跳过以使这个示例尽可能短。

那么接下来是什么。因为 gui 根本不会被测试,所以我会去 ApplicationModel 测试。在第一个测试中,我们指定 applicationModelInterface 应该有方法 load(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 ) );
    }
}

什么是 XML 文档?它存储xml文件的内容。它可以表示为文件行的向量。我们的 AppModelLoader 会将其解析为对象。XFileLoader 是另一个层,它允许我在单元测试中摆脱文件操作。这里它是模拟的,但在真正的应用程序中,它应该被替换为可以读取 xml 文件并返回 XMLDocument 的东西。Data 是一个用于存储解析数据的类。如果 xml 的内容是“<Person><name>Tom</name><age>34</age></Person>,那么数据将如下所示:

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 部分并将其组合起来。

让我知道这是否有意义。

于 2013-10-25T19:33:08.127 回答