我很难让一个间谍bean进入我的ApplicationContext。我有一个类型为 Utilities 的名为 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>
但是,即使我创建了间谍bean并使用了when / thenReturn,它也不会浮动到我的应用程序上下文中等待被调用并返回其模拟的随机值。
我知道方法Utility.getRandom()会被调用,因为我可以在其上放置一个断点并调试测试,并且命中了getRandom方法,但是当我尝试添加如上所示的间谍bean并进行模拟时取出getRandom返回固定值以测试仍然击中的断点,因此我可以告诉真正的方法不是正在调用模拟。
我还尝试将when / thenReturn放入测试中,以防为时过早,但无济于事。
很明显,我在做错事,可能在概念上是错的。死了!
答案 0 :(得分:1)
我试图以最小的配置重新创建您的问题:
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {Ctx.class})
public class XTest {
@SpyBean
private Random random1;
@Autowired private Supplier<Integer> intSupplier;
@Test
public void test() {
Mockito.when(random1.nextInt()).thenReturn(Integer.MAX_VALUE);
int i = intSupplier.get();
System.out.println("i=" + i);
}
@Configuration
public static class Ctx {
@Bean
static Random random1() {
return ThreadLocalRandom.current();
}
@Bean
static Supplier<Integer> intSupplier(Random random1) {
return random1::nextInt;
}
}
}
并按预期打印
i=2147483647
因此,您的运行时配置必定有问题...您能分享一下吗?我猜想spring-integration正在使用另一个ApplicationContext。我知道这不是答案,如果没有帮助,我会删除它。
答案 1 :(得分:0)
好的,谢谢大家的帮助。毫无疑问,发布配置和流程对我来说无济于事,原因如下:
仔细检查时有例外:
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不会接受间谍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;否则,请执行以下步骤:阅读日志;您永远不可能有足够的间接:)