在使用 Spring 进行集成测试期间模拟外部服务器

2024-05-02

我有一个 Spring Web 服务器,它根据请求对某些第三方 Web API 进行外部调用(例如检索 Facebook oauth 令牌)。从该调用获取数据后,它会计算响应:

@RestController
public class HelloController {
    @RequestMapping("/hello_to_facebook")
    public String hello_to_facebook() {
        // Ask facebook about something
        HttpGet httpget = new HttpGet(buildURI("https", "graph.facebook.com", "/oauth/access_token"));
        String response = httpClient.execute(httpget).getEntity().toString();
        // .. Do something with a response
        return response;
    }
}

我正在编写一个集成测试,检查在我的服务器上点击 url 是否会产生一些预期的结果。不过,我想在本地模拟外部服务器,这样我什至不需要访问互联网来测试这一切。做这个的最好方式是什么?

我是春天的新手,这就是我目前所拥有的。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest({})
public class TestHelloControllerIT {        
    @Test
    public void getHelloToFacebook() throws Exception {
        String url = new URL("http://localhost:8080/hello_to_facebook").toString();
        //Somehow setup facebook server mock ...
        //FaceBookServerMock facebookMock = ...

        RestTemplate template = new TestRestTemplate();
        ResponseEntity<String> response = template.getForEntity(url, String.class);
        assertThat(response.getBody(), equalTo("..."));

        //Assert that facebook mock got called
        //facebookMock.verify();
    }
}

实际的设置更复杂——我正在进行 Facebook oauth 登录,所有逻辑都不在控制器中,而是在各种 Spring Security 对象中。但是我怀疑测试代码应该是相同的,因为我只是点击网址并期望得到响应,不是吗?


在尝试了各种场景之后,这是一种如何在对主代码进行最少干预的情况下实现所要求的目标的一种方法

  1. 重构您的控制器以使用第三方服务器地址的参数:

    @RestController
    public class HelloController {
        @Value("${api_host}")
        private String apiHost;
    
        @RequestMapping("/hello_to_facebook")
        public String hello_to_facebook() {
            // Ask facebook about something
            HttpGet httpget = new HttpGet(buildURI("http", this.apiHost, "/oauth/access_token"));
            String response = httpClient.execute(httpget).getEntity().toString();
            // .. Do something with a response
            return response + "_PROCESSED";
        }
    }
    

'api_host' 等于 src/main/resources 中 application.properties 中的 'graph.facebook.com'

  1. 在 src/test/java 文件夹中创建一个新的控制器来模拟第三方服务器。

  2. 覆盖“api_host”以测试“localhost”。

为了简洁起见,以下是将步骤 2 和 3 的代码放在一个文件中:

@RestController
class FacebookMockController {
    @RequestMapping("/oauth/access_token")
    public String oauthToken() {
        return "TEST_TOKEN";
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest({"api_host=localhost",})
public class TestHelloControllerIT {        
    @Test
    public void getHelloToFacebook() throws Exception {
        String url = new URL("http://localhost:8080/hello_to_facebook").toString();
        RestTemplate template = new TestRestTemplate();
        ResponseEntity<String> response = template.getForEntity(url, String.class);
        assertThat(response.getBody(), equalTo("TEST_TOKEN_PROCESSED"));

        // Assert that facebook mock got called:
        // for example add flag to mock, get the mock bean, check the flag
    }
}

有更好的方法来做到这一点吗?感谢所有反馈!

附:以下是我将这个答案放入更现实的应用程序时遇到的一些复杂情况:

  1. Eclipse 将测试和主配置混合到类路径中,因此您可能会通过测试类和参数搞砸主配置:https://issuetracker.springsource.com/browse/STS-3882 https://issuetracker.springsource.com/browse/STS-3882使用 gradle bootRun 来避免它

  2. 如果您设置了 Spring Security,则必须在安全配置中打开对模拟链接的访问。要附加到安全配置而不是弄乱主配置配置:

    @Configuration
    @Order(1)
    class TestWebSecurityConfig extends WebSecurityConfig {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .antMatchers("/oauth/access_token").permitAll();
            super.configure(http);
        }
    }
    
  3. 在集成测试中点击 https 链接并不简单。我最终使用带有自定义请求工厂和配置的 SSLConnectionSocketFactory 的 TestRestTemplate。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在使用 Spring 进行集成测试期间模拟外部服务器 的相关文章

随机推荐

  • 为什么宇宙飞船与盒子对撞机相撞后不再回头?

    我希望当发生碰撞时将宇宙飞船转回来 但他们继续前进 开箱即用的对撞机和地形 使克隆船在碰撞时我想返回的脚本 using System using UnityEngine using Random UnityEngine Random usi
  • Firebase 云存储规则可以根据 Firestore 数据进行验证吗?

    我们可以使用 Firestore 数据授予或限制对 Firebase 云存储上托管的文件的访问权限吗 我想用作 Firebase 安全规则的示例 allow write if get databases mydbname documents
  • `.gitignore` 用于具有 Android 目标的 Ionic 项目

    我正在使用 Capacitor 创建一个 Ionic 项目 编辑 与 Cordova 相比更新的推荐框架 并添加 Android 作为目标 我已经能够构建应用程序并添加 Android 目标 这会在android using ionic b
  • 在 Boost Log 中,如何使用格式字符串格式化自定义严重性级别?

    我在我的 C 程序中使用 boost log 并且我有一个自定义severity logger lt severity level gt 使用我定义的严重级别枚举 然后我使用格式字符串创建日志接收器 TimeStamp ThreadID S
  • 子字符串替换正则表达式 Notepad++

    我正在尝试使用 Notepad 来替换一些文本 我是使用正则表达式的新手 但遇到了问题 替换以下形式的任何模式 CHARACTERS with characters e g SOMEDATA 变成 somedata 这就是我的情况 有什么建
  • Jenkins Git 参数插件无法获取标签

    詹金斯版本 1 593 Git 参数插件 0 4 0 GIT 客户端插件 1 16 1 我使用私有 git 存储库 可以通过 ssh 访问 我的构建是参数化的 git参数是TAG TO BUILD 要构建的分支是refs tags TAG
  • 如何从github项目获取jar? [复制]

    这个问题在这里已经有答案了 我想使用官方网站上的 kSoap2 android 库http simpligility github io ksoap2 android index html http simpligility github
  • Vue Chart.js - 数据变化时图表不更新

    我正在使用 Vue js 和 Chart js 绘制一些图表 每次我调用该函数时generateChart 图表不会自动更新 当我在 Vue Devtools 中检查数据时 它们是正确的 但图表没有反映数据 但是 当我调整窗口大小时 图表确
  • Python - Map/Reduce - 如何在使用 DISCO 计数单词示例中读取 JSON 特定字段

    我正在按照 DISCO 示例来计算文件中的单词数 将单词数作为 Map Reduce 作业 http discoproject org doc disco start tutorial html 我对此工作没有任何问题 但是我想尝试从包含
  • C# 中的私有“集合” - 无法理解它

    我见过很多使用类似的东西编写的示例代码 请原谅这是多么可怕的罐头 public class Test public object Thingy get private set 不幸的是 这些例子从未真正解释为什么 set 被设置为私有 所以
  • numpy.polyfit 没有关键字“cov”

    我试图使用 polyfit 来找到一组数据的最佳拟合直线 但我还需要知道参数的不确定性 所以我也想要协方差矩阵 在线文档建议我写 polyfit x y 2 cov True 但这给出了错误 类型错误 polyfit 得到了意外的关键字参数
  • Unit::Test 与 Rspec 之间的区别 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我对感兴趣Test Unit and Rspec 有人可以向我解释一下两者之间的主要区别是什么 就它们的运作原理而言 测试 单位更类似于 JUn
  • 具有行进立方体的隐式曲面上的 CSG 操作

    我用行进立方体渲染等值面 或者也许游行广场 https en wikipedia org wiki Marching squares因为这是二维的 我想做集合运算 比如集合差 交集和并集 我认为这很容易实现 只需在两个不同隐式曲面的两个顶点
  • ASP.NET 和 jQuery - 从代码隐藏调用

    这是我以前尝试过解决但放弃的问题 基本上我使用 ModalPopupExtenders 来自 AJAX NET 来显示带有一些内容 文本 控件等 的面板 我从代码隐藏中调用它 而且效果很好 但现在我想用一些 jQuery 对话框替换 Mod
  • RealityKit:更改 ModelEntity 的比例而不改变其位置

    我有一个从 A 点移动到 B 点的 ModelEntity 动画 需要一段时间才能完成 当用户点击 ModelEntity 时 我也想向 ModelEntity 添加收缩动画 我尝试将缩放动画直接添加到 ModelEntity 视图 mov
  • 用索引更新表太慢

    我正在观察我们应用程序的实时系统上的探查器 我发现我们定期 每秒 运行一条更新指令 速度相当慢 每次大约需要400ms 查询包含此更新 这是缓慢的部分 UPDATE BufferTable SET LrbCount LrbCount 1 L
  • 从已排序的 ArrayList 中删除重复项,同时保留重复项中的某些元素

    好吧 一开始我以为这会很简单 但我想不出有效的方法来解决这个问题 我想出了一种蛮力的方法来解决这个问题 但这不是很优雅 我有一个数组列表 Contacts 是一个 VO 类 有多个成员 名称 区域 id ArrayList中存在重复项 因为
  • 无法在 AppSync 响应映射模板中从 RDS 序列化 AWSDate

    我正在使用无服务器 Aurora 作为数据库构建 AppSync 项目 并偶然发现了这个奇怪的错误 Can t serialize value getUsers created at Unable to serialize 2019 09
  • 在组件库中找不到 Angular html 文件

    我正在为 Angular 构建一个组件库 我们将在项目之间共享它 但是当我构建包时 html 文件不会被复制到 dist 文件夹中 我收到错误angular Failed to load text input component html
  • 在使用 Spring 进行集成测试期间模拟外部服务器

    我有一个 Spring Web 服务器 它根据请求对某些第三方 Web API 进行外部调用 例如检索 Facebook oauth 令牌 从该调用获取数据后 它会计算响应 RestController public class Hello