Play framework & CAS - 如何登录功能测试?

Posted

技术标签:

【中文标题】Play framework & CAS - 如何登录功能测试?【英文标题】:Play framework & CAS - How to log in for functional tests? 【发布时间】:2012-08-13 14:55:22 【问题描述】:

我正在使用带有 CAS 3.1 的 Play 1.2.4 作为安全模块。在开发过程中一切正常,我必须登录才能使用我的控制器方法。

但我无法让日志部分在我的功能测试中工作。我用这个问题作为参考: Playframework Secure module: how do you "log in" to test a secured controller in a FunctionalTest?

我的测试如下所示:

@Test
public void testThatIndexPageWorks() 

    final Map<String, String> loginUserParams = new HashMap<String, String>();
    loginUserParams.put("login", "foobar");
    loginUserParams.put("password", "foobar");
    final Response loginResponse = POST("/@cas/authenticate", loginUserParams);

    final Request request = newRequest();
    request.cookies = loginResponse.cookies; // makes the request authenticated
    request.url = "/";
    request.method = "GET";
    final Response response = makeRequest(request);
    assertIsOk(response);

测试在 "POST("/@cas......)" 行失败,但有以下异常:

java.lang.RuntimeException: java.util.concurrent.ExecutionException: play.exceptions.ActionNotFoundException: Action null?ticket=ST-e71ba57f-3f1f-4b71-b16f-0141db78b42f not found
    at play.test.FunctionalTest.makeRequest(FunctionalTest.java:299)
    at play.test.FunctionalTest.makeRequest(FunctionalTest.java:305)
    at play.test.FunctionalTest.POST(FunctionalTest.java:152)
    at play.test.FunctionalTest.POST(FunctionalTest.java:200)
    at play.test.FunctionalTest.POST(FunctionalTest.java:167)
    at ApplicationTest.testThatIndexPageWorks(ApplicationTest.java:53)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at play.test.PlayJUnitRunner$StartPlay$2$1.evaluate(PlayJUnitRunner.java:105)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at play.test.PlayJUnitRunner.run(PlayJUnitRunner.java:55)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:24)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:136)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:117)
    at play.test.TestEngine.run(TestEngine.java:112)
    at controllers.TestRunner.run(TestRunner.java:66)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:548)
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:502)
    at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:478)
    at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:473)
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:161)
    at play.server.PlayHandler$NettyInvocation.execute(PlayHandler.java:257)
    at play.Invoker$Invocation.run(Invoker.java:278)
    at play.server.PlayHandler$NettyInvocation.run(PlayHandler.java:235)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.util.concurrent.ExecutionException: play.exceptions.ActionNotFoundException: Action null?ticket=ST-e71ba57f-3f1f-4b71-b16f-0141db78b42f not found
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:232)
    at java.util.concurrent.FutureTask.get(FutureTask.java:91)
    at play.test.FunctionalTest.makeRequest(FunctionalTest.java:286)
    ... 57 more
Caused by: play.exceptions.ActionNotFoundException: Action null?ticket=ST-e71ba57f-3f1f-4b71-b16f-0141db78b42f not found
    at play.mvc.ActionInvoker.getActionMethod(ActionInvoker.java:590)
    at play.mvc.Controller.redirect(Controller.java:555)
    at play.mvc.Controller.redirect(Controller.java:532)
    at play.mvc.Controller.redirect(Controller.java:501)
    at controllers.modules.cas.MockServer.loginAction(MockServer.java:51)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:548)
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:502)
    at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:478)
    at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:473)
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:161)
    at play.test.FunctionalTest$1.execute(FunctionalTest.java:269)
    at play.Invoker$Invocation.run(Invoker.java:278)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    ... 3 more
Caused by: java.lang.Exception: Controller controllers not found
    ... 22 more

因为我得到了某种票,所以身份验证本身似乎有效。

有谁知道我如何在功能测试中通过 CAS 登录我的应用程序,或者在运行测试时同时禁用 CAS / @With(SecureCAS.class)?

【问题讨论】:

虽然有点晚,但可能对其他人有用...见***.com/a/18604839/1579667,和这个人有同样的问题和同样的答案。 【参考方案1】:

设置 CAS 以使用 MockServer 进行播放测试配置文件,在 application.conf 添加:

%test.cas.mockserver=true

然后

@Test
public void testThatIndexPageWorks() 
        // test with cas functionality
        final Map<String, String> loginUserParams = new HashMap<String, String>();
        loginUserParams.put("login", "foobar");
        loginUserParams.put("password", "foobar");
        loginUserParams.put("serviceUrl", "modules.cas.securecas/authenticate"); // must be set but is not used
        final Response authenticateResponse = POST("/@cas/authenticate", loginUserParams);
        // you get a redirect to the authenticate service: assertEquals(Integer.valueOf(302), authenticateResponse.status);

        // extract the ticket from the redirect url:
        String location = authenticateResponse.getHeader("Location");
        String ticket = location.substring(location.indexOf("ticket=")+7, location.length());
        Logger.debug("ticket: "+ticket);

        // odd workaround: we have to set the port and create the request by ourself, otherwise play is calling the url without port!
        final int port = Http.Request.current() == null ? 80 : Http.Request.current().get().port;
        final Request authenticateRequest = newRequest();
        authenticateRequest.port = port;
        final Response validateResponse = GET(authenticateRequest, "/modules.cas.securecas/authenticate?service=cas/serviceValidate&ticket="+ticket);
        // the response is again a redirect, normally to the initially called page:  assertEquals(Integer.valueOf(302), authenticateResponse.status);
        Logger.debug("Authentication successfull");

         // functional test of a html page:
         final Request request = newRequest();
         request.url = "/";
         request.cookies = validateResponse.cookies; // makes the request authenticated
         request.method = "GET";
         final Response response = makeRequest(request);
         assertIsOk(response);

【讨论】:

以上是关于Play framework & CAS - 如何登录功能测试?的主要内容,如果未能解决你的问题,请参考以下文章

Play Framework 无法连接到 WS

Play Framework Routes 中的 Scala 反引号

Play Framework 1.2.4:#select 模板的选定选项

从 Play Framework 更改 WS API! 2.4 至 2.5

从 Play Framework 控制器返回 JSON 字符串

包 io.ebean 不存在 Play Framework 2.7