单元测试 ModalWindow 的内容刷新失败,而实际功能按预期工作 - 我做错了什么?

发布于 2024-08-12 07:54:30 字数 6220 浏览 4 评论 0原文

所以,我先花了几个小时尝试自己“修复”这个问题,然后像疯子一样在谷歌上搜索,但没有找到任何有帮助的东西,所以现在我在这里。

基本上,我在 Wicket 自己的 ModalWindow 中有一个自定义的 Panel,并且由于我喜欢单元测试,所以我想测试它。这里的具体行为是刷新 ModalWindow 的内容:在我提取此内容的实际代码中,Ajax 事件处理实际上将新内容重新加载到内容面板,我只是删除了这些内容以使其更短。

所以,这里是 Panel 的代码

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

和相应的标记

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

请注意,当在 servlet 容器(例如 Tomcat)中运行时,它可以正常工作 - 这里没有功能错误!

那么什么是那么问题来了?我似乎无法通过单元测试来使其发挥作用!我的面板测试类如下所示

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

,这是运行该程序的堆栈跟踪结果,

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, 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

橙味迷妹 2024-08-19 07:54:30

我要冒险说:将面板组件添加到页面进行测试。

据我所知,您无法测试单个组件,但应该通过获取页​​面并对其进行断言来设置测试。

这是我用来测试的:

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

如果我错了,请纠正我!

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!

风柔一江水 2024-08-19 07:54:30

显示表面上有效的“生产”代码是不一致的。我怀疑变量campaignForm应该是字段表单。

但我认为根本问题是模态窗口本身实际上没有附加到组件,因此无法渲染。

如果在实际代码中,它附加在 MyModalWindowPanel 组件外部的某个位置,那么您肯定也需要将它附加在测试中的某个位置,可能是通过使您的测试构建一个测试页面或一个包含模式窗口和被测组件。

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.

软糖 2024-08-19 07:54:30

我唯一一次遇到“未找到页面”异常是在尝试在面板构造函数中调用 getPage() 时。构造函数在面板添加到页面之前执行,因此什么也找不到......您可能在做类似的事情吗?也许这段代码在生产中有效,但仍然在幕后抛出该错误?

我知道这不是您想要的,但我发现 Selenium 是测试 Web UI 的绝佳工具。 JUnit 非常适合测试逻辑,但 Selenium 更适合确保 UI 中显示正确的内容。它的 GUI 界面等看起来很奇怪,但它工作得很好,如果你深入挖掘一下,脚本 API 很容易访问。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文