【问题标题】:Help with real world TDD using Java使用 Java 帮助处理现实世界的 TDD
【发布时间】:2011-11-04 01:53:10
【问题描述】:

我现在正在寻求帮助,以便将 TDD 用于现实世界的示例。大多数节目都太简单了,并没有真正展示如何测试和重构更复杂的类。这是一个同时使用线程和网络套接字的代码示例。有人可以解释如何为这样的类创建一个独立的单元测试吗?谢谢。

public class BaseHandler  extends Thread {
  protected Socket mClientSocket;
  protected BufferedReader is = null;
  protected BufferedWriter os = null;
  private Logger mLogger = Logger.getLogger(WebTestController.class.getName());
  protected WebTestController mWebTestController;

  /*********************************************************************
   * 
   * @param piPort - int port to listen on
   */
  public BaseHandler(){
  }


  /*********************************************************************** cleanup
   * Ensure sockets are closed as to not run into bind errors
   */
  protected void cleanup() {
    try {
      if (is != null)
        is.close();
      if (os != null)
        os.close();
      if (mClientSocket != null)
        mClientSocket.close();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    mLogger.info("cleaning up a socket");
  }

  /***********************************************************************************
   * Sends a message to the current socket
   * @param pMessage
   */
  protected void writeToSocket(String pMessage){
      try {
          os = new BufferedWriter(
            new OutputStreamWriter(mClientSocket.getOutputStream()));

        }
        catch (IOException e) {
          e.printStackTrace();
          cleanup();
          return;
        }
        try {
            os.write(pMessage, 0, pMessage.length());
            os.flush();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        cleanup();
  }

}

【问题讨论】:

    标签: java tdd


    【解决方案1】:

    为了减少测试问题,可以采取一些实际措施:

    1. 不要让您的类继承 Thread。改为将其设为 Runnable,因为您可以单独测试 Runnable。
    2. 使用dependency injection,以便您可以将 Logger 和 WebTestController 替换为测试版本(请参阅“模拟”)。
    3. 从您的代码中删除尚未执行任何操作的任何内容。然后测试你有什么。仅当您已实施的所有内容都正常工作并经过有效测试证明时才添加新内容

    不过,我强烈建议您阅读一本关于 TDD 和单元测试的好书。简单的教程就是这么简单。它们不涵盖您在现实生活中会遇到的复杂案例。在现实生活中使用 TDD 是完全可能的,但它确实需要一些知识——就像编程一样。

    【讨论】:

    • 这个类甚至不必是可运行的,这个类有很多特性什么都不做。我仍然建议他从一个他希望工作的简单测试用例开始,从头开始上课,只添加通过测试所需的代码。
    【解决方案2】:

    不要创建这样的类。

    最好将您的逻辑分解为与 IO 相关的部分和与并发相关的部分。然后可以测试与 IO 相关的部分,例如,使用模拟套接字实现。

    不过,测试与并发相关的逻辑会更复杂。这取决于您想要实现的行为。

    【讨论】:

    • +1:虽然我只会使用真正的 Socket,而不是模拟一个。
    【解决方案3】:

    AFAIK 您应该从测试驱动开发中的测试用例开始。我建议你从这个类应该首先通过的测试开始,把它当作一个原型。

    你必须创建一个类或子类,它会打开一个 Socket 到一个虚拟的 ServerSocket 并向它发送消息。

    【讨论】:

    • 您仍然需要进行设计,并且在您知道要编写哪些类和方法之前,您甚至无法编写测试:所以这个建议并不能真正帮助您
    • OP 在询问 TDD。如果不完成测试,您将无法完成设计,因此我认为您的区别与 TDD 无关。
    • 在 TDD 中,在编写测试之前,您必须确定要测试的内容。即使迭代地使用 TDD,您也必须在编写测试之前决定要创建的第一个类和第一个方法 - 否则测试将调用什么?
    • 在 TDD 中,设计和测试是第一阶段的一个。 en.wikipedia.org/wiki/Test-driven_development“首先开发人员编写一个失败的自动化测试用例,定义所需的改进或新功能”在此之前没有单独的设计阶段。
    【解决方案4】:

    代码没有“使用”线程,它只是一个派生自java.lang.Thread 的类。没有什么能阻止你直接调用run() 方法,毕竟你是在测试你的类而不是java.lang.Thread 中的功能。

    其实你想测试cleanup()writeToSocket方法,所以也不需要调用run()方法。

    只需创建BaseHandler 的子类,用一些模拟对象初始化该子类中的成员,然后就可以开始了。

    不过,您可能需要进行其他更改以使其余代码更易于测试。我假设这个问题更多是关于对现有代码库进行单元测试,而不是关于 TDD。

    【讨论】:

    • +1:run() 方法继承自 Thread,因此它不执行任何操作。 ;)
    • 这既是因为我需要调整我的思维和开发风格来使用 TDD。我提出这个问题是为了了解如何根据我目前的工作。
    【解决方案5】:

    此类不遵守 SRP(单一责任原则)。你的课逻辑太多了。 相反,您应该将此类拆分为多个较小的类。然后,您通常会使用 Spring 或其他 IoC 框架注入这些类。

    如果您要拆分班级,您会注意到测试会容易得多。您可以为这些组件提供模拟对象,并在每个测试用例中按照您的意愿注入它们,因为它最适合您。

    【讨论】:

      猜你喜欢
      • 2010-12-17
      • 1970-01-01
      • 1970-01-01
      • 2010-11-28
      • 2013-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-31
      相关资源
      最近更新 更多