观察者模式(Observer)
在用各种集成了Junit的ide进行软件开发过程中,对整个测试过程的呈现,各种ide的表现不尽相同,大部分都是用红绿状态条的形式来区分测试用例的成功与失败,如下图是Intellij Idea的测试用例测试成功的状态条。
在Junit中,TestResult类即是目标对象,BaseTestRunner抽象类即是观察者对象,其接口为TestListener,该接口定义了一些方法,用以处理各种事件,比如测试成功,测试失败。
package junit.framework;/**
- A Listener for test progress
/
public interface TestListener {
/*- An error occurred.
/
public void addError(Test test, Throwable t);
/* - A failure occurred.
/
public void addFailure(Test test, AssertionFailedError t);
/* - A test ended.
/
public void endTest(Test test);
/* - A test started.
*/
public void startTest(Test test);
}
- An error occurred.
所有的测试客户端都会继承该BaseTestRunner抽象类,成为一个观察者对象,如Junit自身实现的textui中的TestRunner类。
package junit.textui;/**
- A command line based tool to run tests.
- <pre>
- java junit.textui.TestRunner [-wait] TestCaseClass
- </pre>
- TestRunner expects the name of a TestCase class as argument.
- If this class defines a static <code>suite</code> method it
- will be invoked and the returned test is run. Otherwise all
- the methods starting with "test" having no arguments are run.
- <p>
- When the wait command line argument is given TestRunner
- waits until the users types RETURN.
- <p> 9
- TestRunner prints a trace as the tests are executed followed by a
- summary at the end.
*/
public class TestRunner extends BaseTestRunner { ... }
在测试开始时,在客户端首先会将各个观察者对象在目标对象(TestResult)中进行注册,通常客户端自身就是观察者,只有注册过的观察者才会被通知各种事件的发生。下面是TestResult中注册,删除以及克隆观察者的三个方法。
/** * Registers a TestListener */ public synchronized void addListener(TestListener listener) { fListeners.addElement(listener); } /** * Unregisters a TestListener */ public synchronized void removeListener(TestListener listener) { fListeners.removeElement(listener); } /** * Returns a copy of the listeners. */ private synchronized Vector cloneListeners() { return (Vector)fListeners.clone(); }
测成功后,一旦目标对象自身状态发生变化,就可以通知其上所有注册过的观察者,目标对象不关心具体的观察者如何实现,以及观察者如何对结果进行呈现;
/** * Informs the result that a test will be started. */ public void startTest(Test test) { final int count= test.countTestCases(); synchronized(this) { fRunTests+= count; } for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { ((TestListener)e.nextElement()).startTest(test); } }/**
- Adds a failure to the list of failures. The passed in exception
- caused the failure.
*/
public synchronized void addFailure(Test test, AssertionFailedError t) {
fFailures.addElement(new TestFailure(test, t));
for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
((TestListener)e.nextElement()).addFailure(test, t);
}
}
在目标对象中的代码显示了测试开始时,就通知各个观察者单元测试马上开始,失败时,通知各个观察者测试失败;具体的开始或者失败的逻辑有各个观察者自己实现,目标对象无须关心。
在Junit中,目标对象和测试结果类是同一个类,即TestResult,而且我们发现这个类从单元测试一开始就出现在我们的视线内,从始至终,下一节我们就说说为什么这么做?精彩继续!
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于