Java 如何设置Zk会话(org.zkoss.Zk.ui),以便对扩展GenericForwardComposer的控制器类进行单元测试

Java 如何设置Zk会话(org.zkoss.Zk.ui),以便对扩展GenericForwardComposer的控制器类进行单元测试,java,unit-testing,zk,Java,Unit Testing,Zk,我正在尝试对一个现有的ZK控制器进行单元测试,我想在对我的控制器进行单元测试时,找到一种处理如下调用的方法 Sessions.getCurrent().setAttribute(“from”,from.getValue()); 我很乐意替换有问题的代码,或者为单元测试找到解决方法。我的目标是通过处理NullPointerException 我的测试很简单(这是个不错的起点…) @测试 public void zkControllerDoesMockingInitialisedSuccessfu

我正在尝试对一个现有的ZK控制器进行单元测试,我想在对我的控制器进行单元测试时,找到一种处理如下调用的方法

Sessions.getCurrent().setAttribute(“from”,from.getValue()); 我很乐意替换有问题的代码,或者为单元测试找到解决方法。我的目标是通过处理
NullPointerException

我的测试很简单(这是个不错的起点…)

@测试
public void zkControllerDoesMockingInitialisedSuccessfully()引发异常{
T2TripBigDao接口tripBigDao=createMock(T2TripBigDao.class);
ZkFieldValidator-fieldValidator=createMock(ZkTextFieldValidator.class);
FieldRangeValidator rangeValidator=createMock(DefaultFieldRangeValidator.class);
TripController=新的TripController(tripBigDao、fieldValidator、rangeValidator);
重播(tripBigDao、fieldValidator、rangeValidator);
onClick$getTrips(新事件(“getTrips”);
验证(tripBigDao、fieldValidator、rangeValidator);
//测试目的:只需对正在运行的控制器进行单元测试,就可以开始了。。。。
}

控制器的摘录:

公共类TripController扩展了GenericForwardComposer{
....
public void onClick$getTrips(事件)引发异常{
Sessions.getCurrent().setAttribute(“from”,from.getValue());
Sessions.getCurrent().setAttribute(“to”,to.getValue());
....
}
....

堆栈跟踪的提取:

java.lang.NullPointerException
at com.t2.webservice.controller.alert.TripController.onClick$getTrips(TripController.java:72)
at com.t2.webservice.controller.alert.TripControllerTest.zkControllerDoesMockingInitialisedSuccessfully(TripControllerTest.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

这是关于ZK我最不喜欢的事情之一:它们对单例的使用以及对可测试性的影响

我最终要做的是从我的控制器中删除对它们的单例(,)的任何引用。在正常操作中,这些单例可以被使用,但在测试中它们可以被模拟出来

你怎么做取决于你,我还没有找到我喜欢的模式。
这里有一个想法

public class TripController extends GenericForwardComposer {

    private final TripSessionManager tripSessionManager;

    public TripController() {
        // ZK calls the default constructor
        this(new ZKTripSessionManager());
    }

    protected TripController(TripSessionManager tripSessionManager) {
        this.tripSessionManager = tripSessionManager;
    }

    public void onClick$getTrips(Event event) throws Exception {
        tripSessionManager.setTo(to.getValue());
        tripSessionManager.setFrom(from.getValue());
    }

}
您的
TripSessionManager
将如下所示

public interface TripSessionManager {

    void setTo(String to);

    void setFrom(String from);

}
默认ZK实现依赖于
会话
单例

public ZKTripSessionManager implements TripSessionManager {

    public void setTo(String to) {
        setAttribute("to", to);
    }

    public void setFrom(String from) {
        setAttribute("from", from);
    }

    private void setAttribute(String name, String value) {
        // only valid if called in a ZK managed thread
        Sessions.getCurrent().setAttribute(name, value);
    }

}
通过抽象出实现,您可以使用模拟的
TripSessionManager
测试控制器

@Test
public void test() {
    TripSessionManager mockTripSessionManager = mock(TripSessionManager);
    when(mockTripSessionManager.setTo(anyString()).thenAnswer(...);
    when(mockTripSessionManager.setFrom(anyString()).thenAnswer(...);
    TripController controller = new TripController(mockTripSessionManager);
}
您还可以想象使用依赖项注入框架(如Spring或Guice)管理这些新依赖项的不同方式(例如:避免
new ZKTripSessionManager()