使用Spring WebFlux和WebTestClient获取请求属性
使用Spring WebFlux时,我无法将我正在设置的属性从WebTestClient
绑定到RestController
。
我试了我能想到的两种方法。
首先使用@RequestAttribute
注释,我得到:
无法处理请求[Get/Attributes/Annotation]:响应状态为400,原因为"缺少字符串类型的请求属性‘ATTRIBUTE’"
然后我尝试使用ServerWebExchange,结果null
。
这是我的控制器:
@RestController
@RequestMapping("/attributes")
public class MyController {
@GetMapping("/annotation")
public Mono<String> getUsingAnnotation(@RequestAttribute("attribute") String attribute) {
return Mono.just(attribute);
}
@GetMapping("/exchange")
public Mono<String> getUsingExchange(ServerWebExchange exchange) {
return Mono.just(exchange.getRequiredAttribute("attribute"));
}
}
这是我的失败测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyControllerTest {
@Autowired
ApplicationContext context;
WebTestClient webClient;
@Before
public void setup() {
webClient = WebTestClient.bindToApplicationContext(context)
.configureClient()
.build();
}
@Test
public void testGetAttributeUsingAnnotation() {
webClient.get()
.uri("/attributes/annotation")
.attribute("attribute", "value")
.exchange()
.expectStatus()
.isOk();
}
@Test
public void testGetAttributeUsingExchange() {
webClient.get()
.uri("/attributes/exchange")
.attribute("attribute", "value")
.exchange()
.expectStatus()
.isOk();
}
}
在我的实际应用程序中,我有一个SecurityConextRepository,它从(解码的)标头值设置一些属性,我想要获取这些属性。
解决方案
我在一个测试中遇到了同样的问题,该测试以前使用MockMvc,后来不得不转换为使用WebClient。像@jcfandino一样,我希望WebClient上的.attribute()
方法的工作方式类似于MockMvc的requestAttribute()
。
我还没有发现.attribute()
应该如何使用,但我已经通过添加自定义测试筛选器绕过了整个问题。我不确定此方法是否正确,但由于此问题尚未回答,下面的方法可能对遇到相同问题的人有帮助。
@WebFluxTest(controllers = SomeController.class)
@ComponentScan({ "com.path1", "com.path2" })
class SomeControllerTest {
// define a test filter emulating the server's filter (assuming there is one)
private class AttributeFilter implements WebFilter {
String attributeValue;
public AttributeFilter(String filterAttributeValue) {
attributeValue = filterAttributeValue;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
// add the desired attributes
exchange.getAttributes().put(SomeController.ATTR_NAME, attributeValue);
return chain.filter(exchange);
}
}
// mock the service the controller is dependend on
@MockBean
AppService appService;
// define the test where the controller handles a get() operation
@Test
void testMethod() {
// mock the app service
when(appService.executeService(anyString(), anyString())).thenAnswer(input -> {
// ... return some dummy appData
});
var testClient= WebTestClient.bindToController(new SomeController(appService))
.webFilter(new SomeControllerTest.AttributeFilter("someValue"))
.build();
try {
var response = testClient
.get()
.uri("someroute")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectBody(AppData.class);
} catch (Exception e) {
fail("exception caught in testMethod", e);
}
}
}
相关文章