【问题标题】:Issues in Writing Junit Test cases编写 Junit 测试用例的问题
【发布时间】:2015-06-11 23:52:56
【问题描述】:

我被要求为 Listener.class 编写一个 junit 测试用例。目录的侦听器池和 如果有任何请求,请求就会得到处理。

我遇到的问题是

  • Listener.class 中的许多方法是私有的或受保护的。
  • Listener 是一个线程,它不会像那样启动。在侦听器开始初始化之前执行许多其他任务。

到目前为止的进展:

我面临的另一个问题是在侦听器类内部,如果调用一个方法,它会在内部调用另一个方法,该方法将使用一些私有或受保护的实例字段,并且这些字段值由另一个类设置。

在搜索了许多博客并查看了许多问题后,我得出一个结论,即我们需要编写一个以前称为类的模拟并模仿这些行为。 我通过创建一个新类开始创建模拟类,该类在侦听器启动之前执行任务。现在我的前辈告诉我这不是继续的方法,我所做的只是创建一个新服务器,这些代码没有经过测试。

那么我该如何测试代码呢?

我的程序流程是这样的。

  1. ServerConfiguration.class -> 检查系统配置的地方,jav-verion 等
  2. 读取 Server.xml
  3. ServerService.class -> 列出所有侦听器、适配器并将它们存储在哈希映射中,配置侦听器和适配器的端口
  4. Serverservice.class-> 现在仅启动那些在 .xml 中标记为活动的侦听器。

在我的例子中,监听器是可运行的接口。并且它们被一个线程实例化,

请给我您的意见。

更新

现在我的问题是,如何为方法运行测试用例,当它使用超类的变量时。当我运行测试用例时,它总是会失败,因为这些值没有初始化。接下来我该如何进行?

private boolean params()
      {
        String integrity = "";
        String sWAnswer = "";
        try
        {
          try
          {
            integrity = super.getParam("CHECK_INTEGRITY");
            sWAnswer = super.getParam("WRITE_ANSWER");


            **Some Business Logic** 

          super.info("Request Directory  : " + sRequestPath);
          super.info("Response Directory : " + sResponsePath);
          super.info("Error Directory    : " + sErrorPath);
          }
        }
        catch (Exception ex)
        {
          bCheck = false;
        }
        return bCheck;
      }

【问题讨论】:

  • 听起来您正在测试的代码需要重构以启用单元测试。但是,在这样做之前,最好确保围绕您正在重构的代码进行足够的集成测试,这样您就会知道您的重构是否会破坏某些东西。阅读 Michael Feathers 的 Working Effectively with Legacy Code,了解有关如何测试此类代码的更多详细信息

标签: java junit easymock


【解决方案1】:

我使用 EasyMock 已经有一段时间了,但您可能想查看Partial Mocking 另外我假设“.class”是指“.java”。

我认为根本问题是应该设计一个单元测试来测试代码的一个小功能。你所描述的听起来像是变成了一个集成测试。所以首先,确保你已经定义了你要编写的测试类型,两者都可以使用 junit 框架编写。

通常情况下,您会尽量减少使用 mock 或根本不使用它们来进行集成测试,因为您正在测试您的所有部分是否正确地组合在一起。

对于单元测试,您希望隔离一段业务逻辑并忽略系统的其余部分,而这正是使用模拟允许您做的事情。基本思想是使用 mock 框架来创建一个你不关心的所有涉及的类的 mock。

[为正确性编辑] 如果您需要测试的方法是 private,如果范围修饰符不必要地严格,则将其范围修饰符更改为 protected 可能是有意义的。受保护的访问应该为您的测试提供访问权限(因为您的测试应该与它正在测试的类在同一个包中定义)。

如果您无法更改该特定方法的修饰符,另一种选择是将您需要测试的特定代码提取到具有受保护修饰符的新方法中,并直接从您的测试中调用该新方法。

您似乎需要一个 ServerConfigurationTest.java 类,该类将测试读取一个非常简化的 Server.xml 文件,然后验证您是否正确记录了该文件中的数据。

另外,您需要一个 ServerServiceTest.java 类。您将创建一个 ServerService 用于从 Server.xml 访问数据的任何类的模拟(可能是 ServerConfiguration)。从他们的文档中查看the behavior page。修改后,你会有类似的东西:

  // create and populate testConfigServersList with test data
  expect(configMock.getActiveServers())
  .andReturn(testConfigServersList);

因为是直接调用方法,所以不需要“启动”线程。 junit 类已经被执行。您只是在一些测试对象上设置状态,运行您正在测试的方法,然后验证状态以您期望的方式更改。

然后您将进行第二个看起来相同的测试,但您的测试数据只有非活动服务器,然后您将验证没有启动任何服务器。 EasyMock 将让您验证您的类上的方法是否被调用,但实际上不允许该方法使用称为 Partial Mocking 的功能运行。因此,您将创建 ServerService 的部分模拟并模拟出它实际启动另一台服务器的方法。如果 ServerService 有一个巨大的方法从 ServerConfiguration 读取数据并为每个活动服务器启动一个新服务器,那么您需要重构代码并将新服务器启动提取到一个单独的方法中。

【讨论】:

  • 受保护的方法也是包作用域的,因此如果测试类与 tedsdt 下的代码在同一个包中(但在不同的源代码树中),则测试将能够调用受保护的方法跨度>
  • @Jeff Neet 感谢您的建议。但现在我陷入了另一个问题,我已经在我的问题中更新了这个问题。请看一下。
  • @user3473132 这部分代码是您应该提取方法的完美示例:一些业务逻辑您不想测试超类方法一个子类。因此,改为在与params() 相同的类中创建一个新的受保护方法,该方法接受两个字符串integrity sWAnswer 作为参数。然后,直接从您的测试中调用新方法。这使您可以指定一个可以可靠测试的已知字符串。如果您让 super 指定它,对 super 的更改将破坏您的测试。根据定义,这不是单元测试。
  • @JeffNeet,我正在为遗留类编写单元测试。所以我不允许修改代码。
  • @user3473132 查看EasyMock Docs 中关于“为方法使用存根行为”的部分您可以模拟超类,然后使用类似这样的东西插入您的测试值而不是真正打电话给超级:expect(superMock.getParam("CHECK_INTEGRITY")).andReturn("My test integrity string");
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多