Laravel SSO集成测试遇NotFoundHttpException,寻求联合测试方案
解决Laravel集成测试与外部SSO联合测试的问题
你遇到的核心问题是:Laravel的集成测试工具(比如$this->visit())默认只会解析本地应用的路由,当你修改app.url指向SSO的地址后,它还是会尝试在本地项目的路由列表里找/login,而这个路由属于外部SSO系统,自然会抛出NotFoundHttpException。
下面是几种可行的联合测试方案,你可以根据测试场景选择:
方案一:Mock SSO服务(推荐用于单元/集成测试)
如果你的测试重点是验证本地项目与SSO的交互逻辑,而不是测试SSO本身的功能,最好的方式是用Laravel的HTTP客户端模拟SSO的所有响应,这样不需要依赖外部服务,测试速度也更快。
示例代码:
public function testLoginWithMockedSSO() { // 模拟SSO的关键接口响应 Http::fake([ // 匹配SSO的登录页面请求 '192.168.33.11:8081/login*' => Http::response('<html><form action="/login/submit" method="post"></form></html>', 200), // 模拟登录提交后的重定向(跳回本地项目的回调地址) '192.168.33.11:8081/login/submit' => Http::redirect('http://your-local-app.test/sso/callback?token=mock-valid-token'), // 模拟SSO的用户信息接口,根据返回的token返回用户数据 '192.168.33.11:8081/api/user' => Http::response([ 'id' => 1, 'name' => 'Jasurbek', 'email' => 'test@example.com' ], 200), ]); // 访问本地项目的登录入口(它应该自动跳转到SSO) $response = $this->get('/login?service_id=2'); // 断言成功跳转到SSO的登录页面 $response->assertRedirect('http://192.168.33.11:8081/login?service_id=2'); // 模拟SSO登录完成后的回调请求 $response = $this->get('/sso/callback?token=mock-valid-token'); // 断言用户成功登录并跳转到指定页面 $response->assertRedirect('/dashboard'); $this->assertAuthenticated(); }
方案二:直接测试SSO回调逻辑
如果你的测试目标是验证本地项目处理SSO回调的正确性,可以跳过SSO登录页面的交互,直接构造回调请求传入模拟的合法参数:
public function testSSOCallbackHandlesValidToken() { // 模拟SSO返回的用户信息 $mockUser = [ 'id' => 1, 'name' => 'Jasurbek', 'email' => 'test@example.com' ]; // 拦截SSO的用户信息查询请求,返回模拟数据 Http::fake([ '192.168.33.11:8081/api/user' => Http::response($mockUser, 200), ]); // 直接访问本地项目的SSO回调路由,传入模拟的token $response = $this->get('/sso/callback?token=mock-valid-token'); // 断言用户被正确创建/登录,并且跳转到首页 $response->assertRedirect('/dashboard'); $this->assertDatabaseHas('users', [ 'email' => 'test@example.com' ]); $this->assertAuthenticatedAs(User::whereEmail('test@example.com')->first()); }
方案三:端到端测试(用于完整流程验证)
如果你需要测试从本地项目跳转到SSO、登录、再跳回本地的完整流程,就需要用到浏览器自动化工具(比如Playwright、Selenium),这类工具可以真正在浏览器中跨端口/域名跳转。
以Laravel Playwright包为例,示例代码:
public function testFullLoginFlowWithRealSSO() { // 启动浏览器访问本地项目的登录页 $this->browser->visit('/login?service_id=2'); // 等待页面跳转到SSO的登录页面(8081端口) $this->browser->waitForUrl('http://192.168.33.11:8081/login?service_id=2'); // 在SSO页面填写登录信息 $this->browser->fill('input[name="name"]', 'your-sso-username'); $this->browser->fill('input[name="password"]', 'your-sso-password'); $this->browser->click('button[type="submit"]'); // 等待页面跳转回本地项目的首页 $this->browser->waitForUrl('http://your-local-app.test/dashboard'); // 断言登录成功,页面显示用户名 $this->browser->assertSee('Welcome, Jasurbek'); }
关键提醒
- 不要直接修改
app.url来指向SSO,这个配置是给本地Laravel应用用的,修改后会导致测试工具混淆路由归属。 - 集成测试重点验证本地逻辑,Mock外部服务是最佳实践;端到端测试验证完整流程,但依赖外部服务的可用性。
内容的提问来源于stack exchange,提问作者Jasurbek
相关产品推荐
相关产品推荐

