首页 > 解决方案 > SpyBean 没有被到处注入

问题描述

我很难将间谍 bean 放入我的 ApplicationContext。我有一个名为Utilities类型的实用程序的 bean :

@Component("utilities")
public class Utilities {

<snip>

    /**
     * Returns a random int. This is provided mostly for testing mock-ability
     *
     * @return a random integer
     */
    public int getRandom() {
        return (int) (Math.random() * Integer.MAX_VALUE);
    }
}

它在我的 Spring Integration 流间接引用的类中使用。

然后我有这个木星测试:

@TestInstance(Lifecycle.PER_CLASS)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@ExtendWith(SpringExtension.class)
@ContextConfiguration( classes = {
    XmlLocations.class,
    VisitorManager.class,
    Utilities.class,
    UnixTimeChannel.class
})
@WebMvcTest
//@TestExecutionListeners( { MockitoTestExecutionListener.class })
public class FullIntegrationTest {

    @Autowired
    private MockMvc mvc;

    @SpyBean
    private Utilities utilities;

    private ClientAndServer mockServer;

    private static final int MOCK_SERVER_PORT = 9089;

    @BeforeAll
    public void setUpBeforeClass() {

        Mockito.when(utilities.getRandom()).thenReturn(Integer.MAX_VALUE);

        mockServer = ClientAndServer.startClientAndServer(MOCK_SERVER_PORT);
        RestAssuredMockMvc.mockMvc(mvc);
        (new MockServerPingInit()).initializeExpectations(mockServer);
        (new MockServerFullIntegrationInit()).initializeExpectations(mockServer);
    }

    @Test
    public void t00200_IncomingMessage() {

        RestAssuredMockMvc.given()
            .queryParam("example", "example")
            .when()
            .request("POST", "/api/v1/incoming")
            .then()
            .statusCode(equalTo(200));
    }

<snip>

但是,即使我创建了 spy bean 并在其上使用了 when/thenReturn,它也不会漂浮到我的应用程序上下文中等待被调用并返回它的模拟随机值。

我知道方法 utility.getRandom() 被调用,因为我可以在其上放置一个断点并调试测试,并且它命中 getRandom 方法,但是当我尝试添加如上所示的间谍 bean 并模拟 getRandom返回一个固定值来测试断点仍然命中,所以我可以告诉真正的方法不是模拟被调用。

我也尝试将 when/thenReturn 放入测试中,以防它为时过早,但它没有帮助。

显然我做错了什么,可能在概念上是错误的。哈!

标签: javaspringmockitospring-integration

解决方案


好的,谢谢大家的帮助。由于我在下面发现的内容,我认为发布配置和流程无济于事,这并不令人沮丧:

仔细检查有一个例外:

org.springframework.expression.AccessException: Could not resolve bean reference against BeanFactory

有问题的参考是我在实用程序中使用@SpyBean 的方法:

    <int:transformer
        expression="@utilities.asMap('licence_id', headers[licenceId], 'message', 'Delivered: ' + headers[confirmedMessage], 'secured_session_id', headers[visitorSession].getSecureSessionId())" />

它不是一个单独的 ApplicationContext 而是 SpEL 不会接受 spy bean,因为引用已更改或类似。

所以,我不理会这些实用程序,并在其内部改装了另一个 bean 来生成数字,并在上面使用了 SpyBean。现在 Spring Integration/SpEL 再次感到高兴,因为它使用的实用程序 bean 是正确的,并且模拟发生在该 bean 内部并且对 SpEL 是透明的。

@Component
public class RandomSupplier implements Supplier<Double> {

    @Override
    public Double get() {
        return Math.random();
    }
}

public class FullIntegrationTest {

    @Autowired
    private MockMvc mvc;

    @SpyBean
    private RandomSupplier randomSupplier;

    @Autowired // This is only necessary for the toy test below
    private Utilities utilities;

    @BeforeEach
    public void setupAfterInit() {

        Mockito.when(randomSupplier.get()).thenReturn(0.5);
    }

    @Test
    public void t0() throws IOException {
      System.out.println(utilities.getRandom());
    }
...

现在 Spring Integration/SpEL 再次感到高兴,因为它工作的实用程序 bean 是正确的,并且模拟发生在该 bean 内部。

三个教训:不要在 Spring Integration Flow 中窥探 SpEL 中直接引用的 bean;阅读日志;你永远不会有足够的间接性:)


推荐阅读