`
luogankun
  • 浏览: 18891 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

junit设计模式分析五(观察者模式)

阅读更多

问题
如果测试总是能够正确运行,那么我们将没有必要编写它们。只有当测试失败时测试才是有意义的,尤其是当我们没有预期到它们会失败的时候。更有甚者,测试能够以我们所预期的方式失败。JUnit区分了失败(failures)和错误(errors)。失败的可能性是可预期的,
Junit 中的设计模式
并且以使用断言(assertion)来进行检查。而错误则是不可预期的问题,如ArrayIndexOutOfBoundsException。因此我们必须进行报告测试的进行状况,或者打印到控制台,或者是文件,或者GUI界面,甚至同时需要输出到多种介质。如JUnit提供了三种方式如Text,AWT,Swing这三种运行方式,并且JUnit需要提供方便的扩展接口,这样就存在对象间的依赖关系,当测试进行时的状态发生时(TestCase的执行有错误或者失败等),所有依赖这些状态的对象必须自动更新,但是JUnit又不希望为了维护一致性而使各个类紧密耦合,因为这样会降低它们的重用性,怎样解却这个问题?

 

 

模式的选择
同样需要思考设计模式的适用性,Observer(观察者)模式便是第一个要考虑的。Observer观察者模式是行为模式,又叫做发布-订阅(Publish-Subscribe)模式,模型-视图(Model/View)模式,源-监听器(Source/Listener)模式。具有以下意图“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。这听起来非常适合需求。在JUnit测试用例时,测试信息一旦发生改变,如发生错误或者失败,结束测试等,各种输出就要有相应的更新,如文本输出就要在控制台打印信息,GUI则在图形中标记错误信息等。

 

 

Observer(观察者)模式的构成

1、Subject 提供注册和删除观察者对象的方法,可以保存多个观察者
2、 ConcreteSubject 当它的状态发生改变时,向它的各个观察者发出通知
3、 Observer 定义那些目标发生改变时需要获得通知的对象一个更新接口
4、 ConcreteObserver 实现更新接口

 

Observer模式的代码实现:

Subject:

public interface Subject {
	public void addObserver(Observer observer);
	public void removeObserver(Observer observer);
	public List<Observer> getAll();
	public void notifyAllObservers();
}

 

ConcreteSubject:

public class ConcreteSubject implements Subject {
	
	private List<Observer> list = new ArrayList<Observer>();

	public void addObserver(Observer observer) {
		list.add(observer);
	}

	public List<Observer> getAll() {
		return list;
	}

	public void notifyAllObservers() {
		for (Observer observer : list) {
			observer.update();
		}
	}

	public void removeObserver(Observer observer) {
		list.remove(observer);
	}
}

 

Observer:

public interface Observer {
	public void update();
}

 

ConcreteObserver:

public class ConcreteObserver implements Observer {
	public void update() {
		System.out.println("update");
	}
}

 

Client:

public class Client {
	public static void main(String[] args) {
		Observer o1 = new ConcreteObserver();
		Observer o2 = new ConcreteObserver();
		
		Subject subject = new ConcreteSubject();
		subject.addObserver(o1);
		subject.addObserver(o2);
		
		subject.notifyAllObservers();
	}
}

 

 

junit3.8源码的实现:
首先定义Observer观察者的就是TestListener,它是一个接口,定义了几个方法,说明它监听的几个方法。如测试开始,发生失败,发生错误,测试结束等监听事件的时间点。由具体的类来实现。

// 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 started.
	public void startTest(Test test);

	//A test ended.
	public void endTest(Test test);
}

 

在JUnit里有三种方式来实现TestListener,如TextUI,AWTUi,SwingUI并且很容易使开发人员进行扩展,只需实现TestListener即可。下面看在TextUi方式是如何实现的,它由一个类ResultPrinter实现

 

public class ResultPrinter implements TestListener {
	PrintStream fWriter; * A test ended.
		public PrintStream getWriter() {
		return fWriter;
	}

	public void startTest(Test test) {
	getWriter().print(".");
		}

	public void addError(Test test, Throwable t) {
		getWriter().print("E");
	}

	public void addFailure(Test test, AssertionFailedError t) {
		getWriter().print("F");
	}

	public void endTest(Test test) {
	}
}

 在JUnit中使用TestResult来收集测试的结果,它使用Collecting Parameter(收集参数)设计模式(The Smalltalk Best Practice Patterns中有介绍),它实际是ConcreteSubject,在JUnit中Subject和ConcreteSubject是同一个类,我们看它的实现

public class TestResult extends Object {
	//使用Vector来保存,事件的监听者
	protected Vector fListeners = new Vector();

	// Registers a TestListener
	public synchronized void addListener(TestListener listener) {
		fListeners.addElement(listener);
	}

	//Unregisters a TestListener
	public synchronized void removeListener(TestListener listener) {
		fListeners.removeElement(listener);
	}

	//Informs the result that a test will be started.
	public void startTest(Test test) {
		for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
			((TestListener)e.nextElement()).startTest(test);
		}
	}

	//Adds an error to the list of errors. The passed in exception
	//caused the error.
	public synchronized void addError(Test test, Throwable t) {
		for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
			((TestListener)e.nextElement()).addError(test, t);
		}
	}
	
	//以下省略了addFailure和endTest代码
}

 效果
我们来考虑经过使用Observer模式后给系统的架构带来了那些效果:
1、Subject和Observer之间地抽象耦合一个TestResult所知道的仅仅是它有一系列的观察者,每个观察者都实现TestListener接口,TestResult不必知道任何观察者属于哪一个具体的实现类,这样使TestResult和观察者之间的耦合是抽象的和最小的。
2、支持广播通信被观察者TestResult会向所有的登记过的观察者如ResultPrinter发出通知。这样不像通常的请求,通知的发送不需指定它的接收者,目标对象并不关心到底有多少对象对自己感兴趣,它唯一的职责就是通知它的观察者。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics