开发者

Help with real world TDD using Java

I'm looking for help on now to use TDD for a real world example. Most show are too simple and don't really show how test and re-factor more complicated classes. Here is an example of code that uses both a thread and a network socket. Could someone explain how to create a isolated Unit Test for such a class? Thanks.

public class BaseHandler  extends Thread {
  protected Socket mClientSocket;
  protected BufferedReader is = null;
  protected BufferedWriter os = null;
  private Logger mLogger = Logger.getLogger(WebTestController.class.getName());开发者_StackOverflow中文版
  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();
  }

}


Here's a couple of practical things to do to reduce your testing issues:

  1. Don't have your class inherit Thread. Make it a Runnable instead, because you can test a Runnable in isolation.
  2. Use dependency injection so that you can replace the Logger and the WebTestController with test versions (see "mocking").
  3. Remove anything from your code that doesn't do anything yet. Then test what you have. Add new stuff only when everything you have implemented is working and has valid tests to prove it

However I strongly recommend reading a good book about TDD and unit testing. The simple tutorials are just that - simple. They don't cover the complicated cases that you will run into in real life. It's perfectly possible to use TDD in real life, but it does take some knowledge - just like programming.


Don't create such classes.

It would be better to break your logic into IO-related part and concurrency-related part. Then IO-related part can be tested, for example, with a mock socket implementation.

Testing concurrency-related logic would be more complex, though. It depends on behaviour you want to achieve.


AFAIK you should start with the Test case in Test Drive Development. I suggest you start with the test this class should pass first and treat this as a prototype.

You will have to create a class or sub-class which will open a Socket to a dummy ServerSocket and send messages to it.


The code doesn't "use" a thread, it's just a class derived from java.lang.Thread. Nothing stops you from calling the run() method directly, after all you're testing your class and not the functionality in java.lang.Thread.

In fact you want to test the cleanup() and writeToSocket methods, so there's no need to call the run() method either.

Just create a subclass of BaseHandler, initialize your members in that subclass with some mock objects and you're good to go.

You may need other changes to make the rest of your code easier to test, though. I'm assuming this question is more about unit testing an existing code base and less about TDD.


This class doesn't respect SRP(Single Responsibility Priciple). Your class does too much logic. Instead you should split this class into multiple smaller ones. You usually then inject those classes with Spring or other IoC framework.

If you were to split the class you would notice that it will be much easier to test. You could supply mock objects for those components and inject them as you wish in each test case, as it suits you best.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜