English 中文(简体)
Unit testing ModalWindow s content refresh fails while the actual functionality works as expected - what am I doing wrong?
原标题:

So, I ve spent a couple of hours first trying to "fix" this myself and then Googling like a madman but didn t find anything that would ve helped so now I m here.

Basically I have a custom Panel within Wicket s own ModalWindow and since I like unit testing, I want to test it. The specific behavior here is refreshing the ModalWindow s content: In my actual code from where I extracted this the Ajax event handling actually reloads new stuff to the content panel, I just removed those to make this shorter.

So, here s the Panel s code

package wicket.components;

import org.apache.wicket.ajax.AjaxRequestTarget;

import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.*;

public class MyModalWindowPanel extends Panel {

    private Form form;
    private ModalWindow modal;

    public MyModalWindowPanel(String id, ModalWindow modal) {
        super(id);

        this.setOutputMarkupId(true);
        this.modal = modal;

        initializeForm();    
        addBasicDataFieldsToForm();    
        add(campaignForm);
    }

    private void initializeForm() {
        form = new Form("form");
        form.setOutputMarkupId(true);
    }

    private void addBasicDataFieldsToForm() {
        campaignForm.add(new AjaxButton("infoSubmit",
                         new Model<String>("Ajaxy Click")) {

            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {

                modal.setContent(new MyModalWindowPanel(modal.getContentId(),
                                                        modal));

                modal.show(target);
            }
        });
    }
}

and the corresponding markup

<wicket:panel>
    <form wicket:id="form">
        <input type="submit" value="Ajaxy Click" wicket:id="infoSubmit" />
    </form>
</wicket:panel>

Do note that when run in servlet container such as Tomcat, this works correctly - there s no functional bugs here!

So what s the problem then? I m not seemingly able to get the unit test for this to work! My test class for the panel looks like this

package wicket.components;

import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.util.tester.*;
import junit.framework.TestCase;

public class MyModalWindowPanelTestCase extends TestCase {

    private WicketTester tester;    
    private ModalWindow modal;

    @Override
    protected void setUp() throws Exception {
        tester = new WicketTester();    
        modal = new ModalWindow("modal");

        tester.startPanel(new TestPanelSource() {

            public Panel getTestPanel(String id) {    
                return new MyModalWindowPanel(id, modal);
            }
        });
    }

    public void testReloadingPanelWorks() throws Exception {
        // the next line fails!
        tester.executeAjaxEvent("panel:campaignForm:campaignInfoSubmit",
                                "onclick");
        tester.assertNoErrorMessage();
    }
}

and here s the resulting stacktrace of running that

java.lang.IllegalStateException: No Page found for component [MarkupContainer [Component id = modal]]
    at org.apache.wicket.Component.getPage(Component.java:1763)
    at org.apache.wicket.RequestCycle.urlFor(RequestCycle.java:872)
    at org.apache.wicket.Component.urlFor(Component.java:3295)
    at org.apache.wicket.behavior.AbstractAjaxBehavior.getCallbackUrl(AbstractAjaxBehavior.java:124)
    at org.apache.wicket.ajax.AbstractDefaultAjaxBehavior.getCallbackScript(AbstractDefaultAjaxBehavior.java:118)
    at org.apache.wicket.ajax.AbstractDefaultAjaxBehavior.getCallbackScript(AbstractDefaultAjaxBehavior.java:106)
    at org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow$WindowClosedBehavior.getCallbackScript(ModalWindow.java:927)
    at org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.getWindowOpenJavascript(ModalWindow.java:1087)
    at org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.show(ModalWindow.java:352)
    at wicket.components.MyModalWindowPanel$1.onSubmit(MyModalWindowPanel.java:45)
    at org.apache.wicket.ajax.markup.html.form.AjaxButton$1.onSubmit(AjaxButton.java:102)
    at org.apache.wicket.ajax.form.AjaxFormSubmitBehavior.onEvent(AjaxFormSubmitBehavior.java:143)
    at org.apache.wicket.ajax.AjaxEventBehavior.respond(AjaxEventBehavior.java:177)
    at org.apache.wicket.ajax.AbstractDefaultAjaxBehavior.onRequest(AbstractDefaultAjaxBehavior.java:299)
    at org.apache.wicket.util.tester.BaseWicketTester.executeAjaxEvent(BaseWicketTester.java:1236)
    at org.apache.wicket.util.tester.BaseWicketTester.executeAjaxEvent(BaseWicketTester.java:1109)
    at wicket.components.MyModalWindowPanelTestCase.testReloadingPanelWorks(MyModalWindowPanelPanelTestCase.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at junit.framework.TestCase.runTest(TestCase.java:168)
    at junit.framework.TestCase.runBare(TestCase.java:134)
    at junit.framework.TestResult$1.protect(TestResult.java:110)
    at junit.framework.TestResult.runProtected(TestResult.java:128)
    at junit.framework.TestResult.run(TestResult.java:113)
    at junit.framework.TestCase.run(TestCase.java:124)
    at junit.framework.TestSuite.runTest(TestSuite.java:232)
    at junit.framework.TestSuite.run(TestSuite.java:227)
    at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

So, how can/should I fix my unit test so that it would pass?

最佳回答

I m gonna go out on a limb here and say: Add your Panel component to a Page for testing..

AFAIK you can t test individual components, but should set up a test by getting a page and doing asserts on that..

This is what I use for testing:

public class TestHomePage {
    private static WicketTester tester;

    @BeforeClass
    public static void setUp() {
        tester = new WicketTester(new WicketApplication() {
            @Override
            protected void init() {
                //Override init to use SpringUtil s SpringContext due to missing WebApplicationContext
                addComponentInstantiationListener(new SpringComponentInjector(this, SpringUtil.getContext()));
            }
        });
    }

    @Test
    public void testRenderMyPage() {
        //start and render the test page
        tester.startPage(HomePage.class);

        //assert rendered page class
        tester.assertRenderedPage(HomePage.class);

        //assert page contents
        tester.assertContains("Welcome to my webpage");
    }
}

Please do correct me if I m wrong!

问题回答

The "production" code shown that ostensibly works is inconsistent. I suspect the variable campaignForm is supposed to be the field form.

But I think the root problem is that the modal window itself is nowhere actually attached to a component, and thus cannot be rendered.

If in the real code, it s attached somewhere outside your MyModalWindowPanel component, you ll definitely need to attach it somewhere in the test as well, likely by making your test build either a test page or a test panel that contains both the modal window and the component under test.

The only time I ve gotten that "No Page Found" exception was when trying to call getPage() in a panel constructor. The constructor is executed before the panel gets added to a page, so nothing is found... Are you perhaps doing something like that? Perhaps this code works in production, but is still throwing that error behind the scenes?

I know it s not what you are looking for, but I ve found Selenium to be a great tool for testing web UI s. JUnit is awesome for testing logic, but Selenium is better suited for making sure the right thing displays in your UI. It looks hinky with it s gui interface and such, but it works great, and if you dig a bit the scripting api is easily accessible.





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签