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

时间:2013-08-02 14:45:51

标签: java unit-testing zk

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

Sessions.getCurrent().setAttribute("from", from.getValue());

我很乐意更换有问题的代码,或者为单元测试找到解决方法。我的目标是通过处理NullPointerException

来测试可测试性

我的测试很简单(开始的地方也不错......)

    @Test
    public void zkControllerDoesMockingInitialisedSuccessfully() throws Exception {

    T2TripBigDaoInterface tripBigDao = createMock(T2TripBigDao.class);
    ZkFieldValidator fieldValidator = createMock(ZkTextFieldValidator.class);
    FieldRangeValidator rangeValidator = createMock(DefaultFieldRangeValidator.class);

    TripController controller = new TripController(tripBigDao, fieldValidator, rangeValidator);


    replay(tripBigDao, fieldValidator, rangeValidator);

    controller.onClick$getTrips(new Event("getTrips"));

    verify(tripBigDao, fieldValidator, rangeValidator);

    // Test purpose: Just get a unit test of the controller running to start with....
}

<小时/> 控制器的摘录:

public class TripController extends GenericForwardComposer {

....

   public void onClick$getTrips(Event event) throws Exception {
       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)

1 个答案:

答案 0 :(得分:1)

这是我最不喜欢ZK的事情之一:他们对单身人士的使用以及对可测试性的影响。

我最终要做的是从控制器中移除对其单身人士(SessionsExecutionsSelectors)的任何引用。在正常操作中,这些单例会被使用,但在测试中它们可以被嘲笑。

你如何解决这个问题取决于你,我还没有找到一个我喜欢的模式 这是一个想法..

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实现依赖于Sessions单例..

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())。