一个演示Junit4实现原理的ut

文|码术张

本文旨在说明Junit4源代码的设计思想。
说明方式上,使用的是自己的一个创新的想法:
用一个ut来说明。

代码如下;

package test;

import org.junit.Test;

public class IpTest {

    @Test
    public void should_True() throws Exception{
        MyNotifier notifier = new MyNotifier();
        MyResult result = new MyResult();
        notifier.addListener(result.createListener());
        notifier.addListener(new Detail());
        MyDescription description = MyDescription.createMyDescriptionn("IpTest", "");

        notifier.fireTestRunStarted(description);

            MyDescription descriptionForA = MyDescription.createMyDescriptionn("IpTest", "methodA");

            notifier.fireTestStarted(descriptionForA);
            System.out.println("Hi..., I am method A");
            notifier.fireTestFinished(descriptionForA);

            MyDescription descriptionForB = MyDescription.createMyDescriptionn("IpTest", "methodB");
            notifier.fireTestStarted(descriptionForB);
            System.out.println("Hi..., I am method B");
            notifier.fireTestFinished(descriptionForB);

        notifier.fireTestRunFinished(result);

    }

}

类图:


类图

交互图:


交互图

在class IpTest中,有一个should_True方法。
这个方法的实现,即演示了Junit4的实现原理。
MyNotifier、MyResult、MyDescription,
对就Junit源码中类Notifier、Result、Description。

程序运行时,首先发布一个事件fireTestRunStarted;
运行结束时,发布一个一个事件fireTestRunFinished。

类的每一个方法运行时,首先发布一个事件fireTestStarted;
类的每一个方法结束时,会发现一个事件fireTestFinished。

Listener收到事件后,会做一些操作。
这些操作的结果会在程序结时,打印出来:


运行结果

在Junit源代码中,每个方法会有一个用职责链模式构建一个Statement类的对象。
一个方法的执行,即是依次执行这个链表上的语句。
这点没在本文中体现。

本文所用的其他代码如下:

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MyNotifier {
    private final List fListeners =
    Collections.synchronizedList(new ArrayList());

    public void addListener(MyRunListener listener) {
        fListeners.add(listener);
    }

    public void fireTestRunStarted(final MyDescription description) throws Exception {
        for (MyRunListener each : fListeners) {
                each.testRunStarted(description);
        }

    }

    public void fireTestRunFinished(final MyResult result) throws Exception{
        for (MyRunListener each : fListeners) {
                each.testRunFinished(result);
        }

    }

    public void fireTestStarted(final MyDescription description) throws Exception{
        for (MyRunListener each : fListeners) {
                each.testStarted(description);
        }       

    }

    public void fireTestFinished(final MyDescription description)   throws Exception{
        for (MyRunListener each : fListeners) {
                each.testFinished(description);
        }   

    }
}

package test;

import java.util.concurrent.atomic.AtomicInteger;

public class MyResult {

    private AtomicInteger fCount = new AtomicInteger();
    private long fRunTime = 0;
    private long fStartTime;

    public int getRunCount() {
        return fCount.get();
    }

    public long getRunTime() {
        return fRunTime;
    }   

    private class Listener extends MyRunListener {
        @Override
        public void testRunStarted(MyDescription description) throws Exception {
            fStartTime = System.currentTimeMillis();
        }

        @Override
        public void testRunFinished(MyResult result) throws Exception {
            long endTime = System.currentTimeMillis();
            fRunTime += endTime - fStartTime;
        }

        @Override
        public void testFinished(MyDescription description) throws Exception {
            fCount.getAndIncrement();
        }

    }   

    public MyRunListener createListener() {
        return new Listener();
    }
}

package test;

import org.junit.runner.notification.Failure;

public class Detail  extends MyRunListener {
    public void testRunStarted(MyDescription description) throws Exception {
        println("==>JUnit4 started with description: \n" + description);
        println();

      }

      public void testRunFinished(MyResult result) throws Exception {
        println("==>JUnit4 finished with result: \n" + describe(result));
      }

      public void testStarted(MyDescription description) throws Exception {
        println("==>Test method started with description: " + description);
      }

      public void testFinished(MyDescription description) throws Exception {
        println("==>Test method finished with description: " + description);
        println();
      }

      public void testFailure(Failure failure) throws Exception {
        println("==>Test method failed with failure: " + failure);
      }

      public void testAssumptionFailure(Failure failure) {
        println("==>Test method assumption failed with failure: " + failure);
      }

      public void testIgnored(MyDescription description) throws Exception {
        println("==>Test method ignored with description: " + description);
        println();
      }

      private String describe(MyResult result) {
        StringBuilder builder = new StringBuilder();
        builder.append("\tRunCount: " + result.getRunCount())
            .append("\n");
        ;
        builder.append("\tRunTime: " + result.getRunTime())
            .append("\n");

        ;
        return builder.toString();
      }

      private void println() {
        System.out.println();
      }

      private void println(String content) {
        System.out.println(content);
      }
}

package test;

public class MyDescription {
    private  String fclassName;
    private  String fMethodName;

    public String getMethodName() {
        return fMethodName;
    }

    public String getClassName() {
        return fclassName;
    }

    @Override
    public String toString() {
        return getDisplayName();
    }

    /**
     * @return a user-understandable label
     */
    public String getDisplayName() {
        return formatDisplayName(fMethodName, fclassName);
    }

    private MyDescription(String className, String methodName) {
        fclassName = className;
        fMethodName = methodName;
    }

    public static MyDescription createMyDescriptionn(String className, String methodName) {
        return new MyDescription( className,  methodName);
    }

    private static String formatDisplayName(String name, String className) {
        return String.format("%s(%s)", name, className);
    }

}

你可能感兴趣的:(一个演示Junit4实现原理的ut)