如何解决单元测试Spring Cloud Gateway RouteLocator customRouteLocatorRouteLocatorBuilder routeLocatorBuilder
我想使用JUnit5对Spring Cloud Gateway RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){方法进行正确的单元测试。
但是,我很难确定要测试的内容,要声明的内容,要模拟的内容,如何提高覆盖率等。 如果可能的话,我只想对此进行单元测试,而无需启动整个SpringTest等。
@Bean
@Override
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
return routeLocatorBuilder.routes()
.route("forward_to_service_one",r -> r.path("/serviceone/**").and().uri("http://the-first-service:8080"))
.route("forward_to_service_two",r -> r.path("/servicetwo/**").and().uri("http://the-second-service:8080"))
.route("forward_to_service_three",r -> r.alwaysTrue().and().order(Ordered.LOWEST_PRECEDENCE).uri("http://the-default-third-service:8080"))
.build();
}
在进行集成测试时,点击在端点上启动的网关服务,查看转发到各个服务的请求,我想知道是否有好的实践来测试此Spring Cloud Gateway功能。
请问有涵盖全部测试用例的示例吗?
谢谢
解决方法
我无法理解您的测试场景(如果为该路径正确配置了服务,您想测试什么?)但是我想向您展示2种方法,第一种是基本方法,第二种是更多方法如果您需要更多控制,那就麻烦了。
简单
这很简单,我在SpringBootTest属性中添加了一些路由,我使用了Spring提供给我的WebTestClient实用程序来进行Netty的响应式测试。然后在我的测试中,我只是向此 / test 端点发送请求,并期望它已配置(根据您的实现,如果您不扩展Spring Cloud Gateway,我可以说此测试无用,我们不应该测试Spring Cloud Gateway的功能,但是无论如何,这是我从您的描述中所了解的信息
@RunWith(SpringRunner.class)
@SpringBootTest(properties = {
"spring.cloud.gateway.routes[0].id=test","spring.cloud.gateway.routes[0].uri=http://localhost:8081","spring.cloud.gateway.routes[0].predicates[0]=Path=/test/**",},webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class NettyRoutingFilterTests {
@Autowired
private ApplicationContext context;
@Test
@Ignore
public void mockServerWorks() {
WebTestClient client = WebTestClient.bindToApplicationContext(this.context)
.build();
client.get().uri("/test").exchange().expectStatus().isOk();
}
复杂
第二种方法可能是从源代码中将模拟路线定位器设置为上下文,并调用服务,声明响应。这与从SpringBootProperties设置路由不同,当您出于某种原因需要一些控制时(在我的情况下,我们使用的是合同测试,我将不做详细介绍),但这是一些模拟,我没有尝试完整的示例(但是在我的项目中使用相同的方法),但应该可以为您提供想法和一些起点;
@ExtendWith( { SpringExtension.class } )
@SpringBootTest(classes = { MockConfigurer.class },webEnvironment = WebEnvironment.RANDOM_PORT )
public class RoutingIT
{
@LocalServerPort
private int port;
您应该像下面那样模拟路由,以便在请求时返回我们的ServiceInstance。在下一步中,我们还将把ServiceInstance放到上下文中。 (我在这里使用发现客户端,我的路由从领事/尤里卡那里返回,但是这里重要的一点是上下文中有RouteDefinitions。如果您正在使用其他定位器,请检查RouteDefinitionLocator的实现,并根据该路由将相应的路由注入到您的上下文中);
@Configuration
public class MockConfigurer
{
private List<ServiceInstance> services;
public MockConfigurer( List<ServiceInstance> services)
{
this.services= services;
}
@Bean
public DiscoveryClient discoveryClient( )
{
final DiscoveryClient mock = mock( DiscoveryClient.class );
final Map<String,List<ServiceInstance>> clusters =
this.services.stream( ).collect( Collectors.groupingBy( ServiceInstance::getServiceId ) );
given( mock.getServices( ) ).willReturn( new ArrayList<>( clusters.keySet( ) ) );
clusters.forEach( ( clusterId,services ) -> given( mock.getInstances( clusterId ) ).willReturn( services ) );
return mock;
}
}
现在在您的测试中实现MockService;
public class MockService implements ServiceInstance
{
// fields,constructors
@Override
public String getServiceId( )
{
return id;
}
@Override
public int getPort( )
{
return port;
}
// and other functions as well,but you will get the point
在您的测试中创建此MockService的实例,并将其注入到spring上下文中,以便可以将它们作为我们以前的MockConfigurer作为服务来发现;
@Bean
public static MockService mockClusterInstance1( )
{
return new MockService("test",8081,// more fields based on your implementation,also pay attention this is what we defined in the @SpringBootTest annotation);
}
现在一切都可以测试了。
@Test
public void should_GetResponseFromTest_WhenCalled( ) throws Exception
{
URI uri= new URI( "http://localhost:" + this.port+ "/test");
ResponseEntity<String> res = this.restTemplate.getForEntity( uri,String.class );
assertThat( res.getStatusCodeValue( ) ).isEqualTo( HttpURLConnection.HTTP_OK );
assertThat( res.getBody( ) ).isEqualTo( // your expectation );
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。