单元测试Spring Cloud Gateway RouteLocator customRouteLocatorRouteLocatorBuilder routeLocatorBuilder

如何解决单元测试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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-