使用带有Mockito和Wicket的@ javax.inject.Inject模拟注入的字段会导致Wicket将字段视为子组件

时间:2016-07-21 12:40:20

标签: mockito wicket cdi

我有一个带有CDI注入字段的WicketPage,如下所示:

public class Page extends BaseWebPage {
private static final long serialVersionUID = 1L;

@Inject
private Facade facade;

public Page () {
    super("Title");
}
}

我有一个单元测试,我嘲笑这个字段:

@RunWith(MockitoJUnitRunner.class)
public class PageTest{

    @Mock
    private Facade facadeMock;

    @InjectMocks
    private Page cut;

    WicketTester tester = new WicketTester(new MockApplication());

    @Before
    public void setUp() {
        Entity entity = newEntity("1", "John"));
        Mockito.when(facadeMock.find()).thenReturn(entity );
    }

    @Test
    public void testOverzicht() {
        tester.startPage(cut);
//below line throws stackTrace
        tester.assertRenderedPage(Page.class);
    }
}
奇怪的是,Wicket无法理解我注入的Mock。在某个时刻,Wicket开始处理它的组件,其中facadeMock突然之一。然后它失败了一个组件检查的实例,因为它失败了 是一个Mockito的代理,导致Wicket抛出IllegalArgumentException。然后它继续解析,然后将facadeMock转换为它的分离方法中的Object []。下面添加了Stacktrace以澄清导致classCastException。

注意:出于隐私原因,类和包的名称会被更改。

java.lang.IllegalArgumentException: Unknown type of object facadeMock
    at org.apache.wicket.MarkupContainer.getId(MarkupContainer.java:1068)
    at org.apache.wicket.MarkupContainer.children_indexOf(MarkupContainer.java:1130)
    at org.apache.wicket.MarkupContainer.put(MarkupContainer.java:1318)
    at org.apache.wicket.MarkupContainer.add(MarkupContainer.java:175)
    at nl.app.Page.onInitialize(Page.java:53)
    at org.apache.wicket.Component.fireInitialize(Component.java:877)
    at org.apache.wicket.MarkupContainer.internalInitialize(MarkupContainer.java:961)
    at org.apache.wicket.Page.isPageStateless(Page.java:463)
    at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:244)
    at org.apache.wicket.util.tester.BaseWicketTester$LastPageRecordingPageRendererProvider$1.respond(BaseWicketTester.java:2755)
    at org.apache.wicket.core.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:175)
    at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:890)
    at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)
    at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:261)
    at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:218)
    at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:289)
    at org.apache.wicket.util.tester.BaseWicketTester.processRequest(BaseWicketTester.java:712)
    at org.apache.wicket.util.tester.BaseWicketTester.processRequest(BaseWicketTester.java:651)
    at org.apache.wicket.util.tester.BaseWicketTester.startPage(BaseWicketTester.java:876)
    at org.apache.wicket.util.tester.BaseWicketTester.startPage(BaseWicketTester.java:893)
    at nl.app.Page.testOverzicht(PageTest.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    at java.lang.reflect.Method.invoke(Method.java:611)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
ERROR [RequestHandlerStack.detach()] Error detaching RequestHandler
java.lang.ClassCastException: nl.app.common.facade.Facade$$EnhancerByMockitoWithCGLIB$$7b6f60ae incompatible w
ith [Ljava.lang.Object;
    at java.lang.ClassCastException.<init>(ClassCastException.java:58)
    at org.apache.wicket.MarkupContainer.children_size(MarkupContainer.java:1305)
    at org.apache.wicket.MarkupContainer.detachChildren(MarkupContainer.java:1603)
    at org.apache.wicket.Component.detach(Component.java:1186)
    at org.apache.wicket.core.request.handler.PageProvider.detach(PageProvider.java:327)
    at org.apache.wicket.core.request.handler.RenderPageRequestHandler.detach(RenderPageRequestHandler.java:156)
    at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.detach(RequestCycle.java:901)
    at org.apache.wicket.request.RequestHandlerStack.detach(RequestHandlerStack.java:180)
    at org.apache.wicket.request.cycle.RequestCycle.onDetach(RequestCycle.java:636)
    at org.apache.wicket.request.cycle.RequestCycle.detach(RequestCycle.java:589)
    at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:293)
    at org.apache.wicket.util.tester.BaseWicketTester.processRequest(BaseWicketTester.java:712)
    at org.apache.wicket.util.tester.BaseWicketTester.processRequest(BaseWicketTester.java:651)
    at org.apache.wicket.util.tester.BaseWicketTester.startPage(BaseWicketTester.java:876)
    at org.apache.wicket.util.tester.BaseWicketTester.startPage(BaseWicketTester.java:893)
    at nl.app.Page.testOverzicht(PageTest.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    at java.lang.reflect.Method.invoke(Method.java:611)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

1 个答案:

答案 0 :(得分:0)

我将建议一种稍微不同的方法,它不会使用@InjectMocks

从CDI的角度来看,实现一个bean在测试(模拟)和实际场景(完全实现)中使用不同实现的行为的方法是使用 @Alternative 。它允许像嘲笑那样做,但是......没有嘲笑任何东西。 CDI spec本身在嘲弄的背景下谈到了替代方案。

它的工作方式如下。首先,您的bean具有真正的实现:

public MyBean {
  public void awesomeMethod() {
    doStuff(); //do what you really want and or need here
  }
}

现在有另一个@Alternative bean扩展你的bean:

@Alternative
public MyMockedBean extends MyBean {
  public void awesomeMethod() {
    // do some other, (mocked) stuff here, or don't do anything at all
  }
}

现在,最后但并非最不重要的是,默认情况下 @Alternative已停用。这意味着CDI通常会忽略它并使用原始bean代替。为了启用它,您可以使用两种方法:

  • @Priority,可以随时全局启用它。在你的情况下你不希望这样。
  • beans.xml,或者更为明确的是,在beans.xml中列出替代方案。这样就可以在每个bean存档的基础上启用替代方案。这是要走的路 - 只需在测试中添加不同的beans.xml并在那里列出@Alternative。这样,您将保留标准behvaiour超出测试范围,并在测试中使用“模拟”bean。

beans.xml应包含以下行,以便启用@Alternative

<alternatives>
  <class>com.whatever.MyMockedBean</class>
</alternatives>