简体   繁体   English

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

[英]How can I set up Zk Sessions (org.zkoss.zk.ui) so I can unit test a controller class extending GenericForwardComposer

I'm trying to unit test an existing ZK controller and I want to find a way to handle a call like the following while unit testing my Controller, 我正在尝试对现有的ZK控制器进行单元测试,并且想在对控制器进行单元测试时找到一种处理如下调用的方法,

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

I'd be happy to either replacing the offending code, or find a way around it for the unit test. 我很乐意替换有问题的代码,或者为单元测试找到解决方法。 My goal is testability by dealing with the NullPointerException 我的目标是通过处理NullPointerException实现可测试性

My test is simple (it's not too bad a place to start...) 我的测试很简单(开始的地方还不错...)

    @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....
}


Extract of the controller: 控制器摘录:

 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()); .... } .... 


Extract of the stack trace: 堆栈跟踪的提取:

 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) 

This is one of the things I dislike most about ZK: their use of singletons and the impact that has on testability. 这是我最不喜欢ZK的事情之一:它们对单例的使用以及对可测试性的影响。

What I end up doing is removing any references to their singletons ( Sessions , Executions , Selectors ) from my controllers. 我最终要做的是从我的控制器中删除对它们的单例( SessionsExecutionsSelectors )的任何引用。 In normal operation these singletons get used, but in tests they can be mocked out. 在正常操作中,这些单例会被使用,但在测试中,它们可以被模拟。

How you go about this is up to you, I still haven't found a pattern I'm in love with. 如何处理取决于您,我仍然没有找到自己喜欢的模式。
Here's one idea.. 这是一个主意。

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());
    }

}

Your TripSessionManager would then look like this.. 然后, TripSessionManager将如下所示。

public interface TripSessionManager {

    void setTo(String to);

    void setFrom(String from);

}

With the default ZK implementation relying on the Sessions singleton.. 默认的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);
    }

}

By abstracting out the implementation, you can test your controller with a mock TripSessionManager .. 通过抽象化实现,可以使用模拟TripSessionManager ..测试您的控制器。

@Test
public void test() {
    TripSessionManager mockTripSessionManager = mock(TripSessionManager);
    when(mockTripSessionManager.setTo(anyString()).thenAnswer(...);
    when(mockTripSessionManager.setFrom(anyString()).thenAnswer(...);
    TripController controller = new TripController(mockTripSessionManager);
}

You could also imagine different ways of managing these new dependencies (eg: avoid new ZKTripSessionManager() ) using dependency injection frameworks like Spring or Guice. 您还可以想象使用像Spring或Guice这样的依赖注入框架来管理这些新依赖的不同方法(例如:避免使用new ZKTripSessionManager() )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM