Coverage Report - org.seasar.cubby.unit.CubbyTestCase
 
Classes in this File Line Coverage Branch Coverage Complexity
CubbyTestCase
38%
31/81
14%
3/22
0
 
 1  
 /*
 2  
  * Copyright 2004-2008 the Seasar Foundation and the Others.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 13  
  * either express or implied. See the License for the specific language
 14  
  * governing permissions and limitations under the License.
 15  
  */
 16  
 package org.seasar.cubby.unit;
 17  
 
 18  
 import static org.seasar.cubby.CubbyConstants.ATTR_ROUTINGS;
 19  
 
 20  
 import java.lang.reflect.Field;
 21  
 import java.util.ArrayList;
 22  
 import java.util.HashMap;
 23  
 import java.util.List;
 24  
 import java.util.Map;
 25  
 import java.util.Map.Entry;
 26  
 
 27  
 import org.seasar.cubby.action.ActionResult;
 28  
 import org.seasar.cubby.action.Forward;
 29  
 import org.seasar.cubby.action.Redirect;
 30  
 import org.seasar.cubby.controller.ActionProcessor;
 31  
 import org.seasar.cubby.controller.ActionResultWrapper;
 32  
 import org.seasar.cubby.controller.ThreadContext;
 33  
 import org.seasar.cubby.routing.InternalForwardInfo;
 34  
 import org.seasar.cubby.routing.Router;
 35  
 import org.seasar.framework.beans.util.Beans;
 36  
 import org.seasar.framework.mock.servlet.MockHttpServletRequest;
 37  
 import org.seasar.framework.mock.servlet.MockHttpServletResponse;
 38  
 import org.seasar.framework.unit.S2TigerTestCase;
 39  
 import org.seasar.framework.util.ClassUtil;
 40  
 import org.seasar.framework.util.StringUtil;
 41  
 
 42  
 /**
 43  
  * CubbyのActionクラスの単体テスト用のクラスです。
 44  
  * <p>
 45  
  * このクラスを継承して、それぞれのActionクラス用の単体テストを作成します。 詳細はCubbyドキュメントの「アクションのテスト」を参照下さい。
 46  
  * 
 47  
  * <pre>
 48  
  * public class HelloActionTest extends CubbyTestCase {
 49  
  *         // 対象のアクション
 50  
  *         private HelloAction action;
 51  
  * 
 52  
  *         // 初期化処理
 53  
  *         protected void setUp() throws Exception {
 54  
  *                 // diconファイルの読み込み
 55  
  *                 include(&quot;app.dicon&quot;);
 56  
  *         }
 57  
  * 
 58  
  *         public void testIndex() throws Exception {
 59  
  *                 // アクションの実行
 60  
  *                 ActionResult result = processAction(&quot;/hello/&quot;);
 61  
  *                 // 結果のチェック
 62  
  *                 assertPathEquals(Forward.class, &quot;input.jsp&quot;, result);
 63  
  *         }
 64  
  * 
 65  
  *         public void setUpMessage() {
 66  
  *                 // リクエストパラメータのセット
 67  
  *                 getRequest().addParameter(&quot;name&quot;, &quot;name1&quot;);
 68  
  *         }
 69  
  * 
 70  
  *         public void testMessage() throws Exception {
 71  
  *                 // アクションの実行
 72  
  *                 ActionResult result = processAction(&quot;/hello/message&quot;);
 73  
  *                 // 結果のチェック
 74  
  *                 assertPathEquals(Forward.class, &quot;result.jsp&quot;, result);
 75  
  *                 // 実行後のアクションの状態を確認
 76  
  *                 assertEquals(&quot;name1&quot;, action.name);
 77  
  *         }
 78  
  * }
 79  
  * </pre>
 80  
  * 
 81  
  * <pre>
 82  
  * public class TodoActionTest extends CubbyTestCase {
 83  
  * 
 84  
  *         private TodoAction action;
 85  
  * 
 86  
  *         public void setUpShow() throws Exception {
 87  
  *                 emulateLogin();
 88  
  *         }
 89  
  * 
 90  
  *         private void emulateLogin() throws Exception {
 91  
  *                 User user = new User();
 92  
  *                 user.setId(&quot;mock&quot;);
 93  
  *                 user.setName(&quot;mock&quot;);
 94  
  *                 user.setPassword(&quot;mock&quot;);
 95  
  *                 getRequest().getSession().setAttribute(&quot;user&quot;, user);
 96  
  *         }
 97  
  * 
 98  
  *         public void testShow() throws Exception {
 99  
  *                 this.readXlsAllReplaceDb(&quot;TodoActionTest_PREPARE.xls&quot;);
 100  
  *                 // CoolURIの場合のテスト
 101  
  *                 ActionResult result = processAction(&quot;/todo/1&quot;);
 102  
  *                 assertPathEquals(Forward.class, &quot;show.jsp&quot;, result);
 103  
  *                 assertEquals(new Integer(1), action.id);
 104  
  *                 assertEquals(&quot;todo1&quot;, action.text);
 105  
  *                 assertEquals(&quot;todo1 memo&quot;, action.memo);
 106  
  *                 assertEquals(new Integer(1), action.todoType.getId());
 107  
  *                 assertEquals(&quot;type1&quot;, action.todoType.getName());
 108  
  *                 assertEquals(&quot;2008-01-01&quot;, action.limitDate);
 109  
  *         }
 110  
  * }
 111  
  * </pre>
 112  
  * 
 113  
  * </p>
 114  
  * 
 115  
  * @author agata
 116  
  * @author baba
 117  
  * @since 1.0.0
 118  
  */
 119  2
 public abstract class CubbyTestCase extends S2TigerTestCase {
 120  
 
 121  
         /** ルーティング */
 122  
         private Router router;
 123  
 
 124  
         /** ActionProcessor */
 125  
         private ActionProcessor actionProcessor;
 126  
 
 127  
         /**
 128  
          * ActionResultの型とパスをチェックします。
 129  
          * 
 130  
          * @param resultClass
 131  
          *            ActionResultの型
 132  
          * @param expectedPath
 133  
          *            期待されるパス
 134  
          * @param actualResult
 135  
          *            チェックするActionResult
 136  
          */
 137  
         public static void assertPathEquals(
 138  
                         final Class<? extends ActionResult> resultClass,
 139  
                         final String expectedPath, final ActionResult actualResult) {
 140  0
                 assertPathEquals(resultClass, expectedPath, actualResult, "UTF-8");
 141  0
         }
 142  
 
 143  
         /**
 144  
          * ActionResultの型とパスをチェックします。
 145  
          * 
 146  
          * @param resultClass
 147  
          *            ActionResultの型
 148  
          * @param expectedPath
 149  
          *            期待されるパス
 150  
          * @param actualResult
 151  
          *            チェックするActionResult
 152  
          * @param characterEncoding
 153  
          *            URI のエンコーディング
 154  
          */
 155  
         public static void assertPathEquals(
 156  
                         final Class<? extends ActionResult> resultClass,
 157  
                         final String expectedPath, final ActionResult actualResult,
 158  
                         final String characterEncoding) {
 159  0
                 assertEquals("ActionResultの型をチェック", resultClass, actualResult
 160  
                                 .getClass());
 161  0
                 if (actualResult instanceof Forward) {
 162  0
                         assertEquals("パスのチェック", expectedPath, Forward.class.cast(
 163  
                                         actualResult).getPath(characterEncoding));
 164  0
                 } else if (actualResult instanceof Redirect) {
 165  0
                         assertEquals("パスのチェック", expectedPath, Redirect.class.cast(
 166  
                                         actualResult).getPath(characterEncoding));
 167  
                 }
 168  0
         }
 169  
 
 170  
         /**
 171  
          * アクションメソッドを実行します。
 172  
          * 
 173  
          * @param originalPath
 174  
          *            オリジナルパス
 175  
          * @return アクションメソッドの実行結果。アクションメソッドが見つからなかったり結果がない場合は <code>null</code>
 176  
          * @throws Exception
 177  
          *             アクションメソッドの実行時に例外が発生した場合
 178  
          */
 179  
         protected ActionResult processAction(final String originalPath)
 180  
                         throws Exception {
 181  1
                 final MockHttpServletRequest request = getRequest();
 182  1
                 setServletPath(request, originalPath);
 183  1
                 final MockHttpServletResponse response = getResponse();
 184  1
                 routing(request, response);
 185  1
                 setupThreadContext();
 186  1
                 final ActionResultWrapper actionResultWrapper = actionProcessor
 187  
                                 .process(request, response);
 188  1
                 if (actionResultWrapper == null) {
 189  0
                         return null;
 190  
                 }
 191  1
                 return actionResultWrapper.getActionResult();
 192  
         }
 193  
 
 194  
         /**
 195  
          * CubbyFilterで行っているルーティングをエミュレートして、内部フォワードパスをリクエストにセットします。
 196  
          * 
 197  
          * @param request
 198  
          *            リクエスト
 199  
          * @param response
 200  
          *            レスポンス
 201  
          * @return 内部フォワードパス
 202  
          * @since 1.0.5
 203  
          */
 204  
         protected String routing(final MockHttpServletRequest request,
 205  
                         final MockHttpServletResponse response) {
 206  1
                 final InternalForwardInfo internalForwardInfo = router.routing(request,
 207  
                                 response);
 208  1
                 if (internalForwardInfo == null) {
 209  0
                         fail(request.getServletPath() + " could not mapping to action");
 210  
                 }
 211  1
                 final String internalForwardPath = internalForwardInfo
 212  
                                 .getInternalForwardPath();
 213  1
                 final MockHttpServletRequest internalForwardRequest = this
 214  
                                 .getServletContext().createRequest(internalForwardPath);
 215  1
                 request.setAttribute(ATTR_ROUTINGS, internalForwardInfo
 216  
                                 .getOnSubmitRoutings());
 217  1
                 request.setAttribute("javax.servlet.forward.request_uri", request
 218  
                                 .getRequestURI());
 219  1
                 request.setAttribute("javax.servlet.forward.context_path", request
 220  
                                 .getContextPath());
 221  1
                 request.setAttribute("javax.servlet.forward.servlet_path", request
 222  
                                 .getServletPath());
 223  1
                 request.setAttribute("javax.servlet.forward.path_info", request
 224  
                                 .getPathInfo());
 225  1
                 request.setAttribute("javax.servlet.forward.query_string", request
 226  
                                 .getQueryString());
 227  1
                 final String servletPath = internalForwardRequest.getServletPath();
 228  1
                 setServletPath(request, servletPath);
 229  1
                 request.setQueryString(internalForwardRequest.getQueryString());
 230  1
                 if (StringUtil.isNotBlank(internalForwardRequest.getQueryString())) {
 231  0
                         final Map<String, List<String>> pathParameters = parseQueryString(internalForwardRequest
 232  
                                         .getQueryString());
 233  0
                         for (final Entry<String, List<String>> entry : pathParameters
 234  
                                         .entrySet()) {
 235  0
                                 final String name = entry.getKey();
 236  0
                                 for (final String value : entry.getValue()) {
 237  0
                                         request.addParameter(name, value);
 238  
                                 }
 239  0
                         }
 240  
                 }
 241  1
                 return internalForwardPath;
 242  
         }
 243  
 
 244  
         /**
 245  
          * 指定されたモックリクエストのサーブレットパスを設定します。
 246  
          * 
 247  
          * @param request
 248  
          *            リクエスト
 249  
          * @param servletPath
 250  
          *            サーブレットパス
 251  
          */
 252  
         private static void setServletPath(final MockHttpServletRequest request,
 253  
                         final String servletPath) {
 254  2
                 final Field servletPathField = ClassUtil.getDeclaredField(request
 255  
                                 .getClass(), "servletPath");
 256  2
                 servletPathField.setAccessible(true);
 257  
                 try {
 258  2
                         servletPathField.set(request, servletPath);
 259  0
                 } catch (final Exception ex) {
 260  0
                         throw new RuntimeException(ex);
 261  2
                 }
 262  2
         }
 263  
 
 264  
         /**
 265  
          * {@link ThreadContext}にリクエストをセットします。
 266  
          */
 267  
         protected void setupThreadContext() {
 268  2
                 ThreadContext.setRequest(getRequest());
 269  2
         }
 270  
 
 271  
         /**
 272  
          * クエリ文字列をパースして {@link Map} へ変換します。
 273  
          * 
 274  
          * @param queryString
 275  
          *            クエリ文字列
 276  
          * @return クエリ文字列をパースした {@link Map}
 277  
          */
 278  
         private Map<String, List<String>> parseQueryString(final String queryString) {
 279  0
                 final Map<String, List<String>> params = new HashMap<String, List<String>>();
 280  0
                 final String[] tokens = queryString.split("&");
 281  0
                 for (final String token : tokens) {
 282  0
                         final String[] param = token.split("=");
 283  0
                         final String name = param[0];
 284  0
                         final String value = param[1];
 285  
                         final List<String> values;
 286  0
                         if (params.containsKey(name)) {
 287  0
                                 values = params.get(name);
 288  
                         } else {
 289  0
                                 values = new ArrayList<String>();
 290  0
                                 params.put(name, values);
 291  
                         }
 292  0
                         values.add(value);
 293  
                 }
 294  0
                 return params;
 295  
         }
 296  
 
 297  
         /**
 298  
          * CubbyFilterで行っているルーティングをエミュレートして、内部フォワードパスをリクエストにセットします。
 299  
          * 
 300  
          * @param orginalPath
 301  
          *            オリジナルパス
 302  
          * @return 内部フォワードパス
 303  
          */
 304  
         @Deprecated
 305  
         @SuppressWarnings( { "unchecked" })
 306  
         protected String routing(final String orginalPath) {
 307  0
                 final MockHttpServletRequest originalRequest = this.getServletContext()
 308  
                                 .createRequest(orginalPath);
 309  0
                 final MockHttpServletResponse response = this.getResponse();
 310  0
                 final InternalForwardInfo internalForwardInfo = router.routing(
 311  
                                 originalRequest, response);
 312  0
                 if (internalForwardInfo == null) {
 313  0
                         fail(orginalPath + " could not mapping to action");
 314  
                 }
 315  0
                 final String internalForwardPath = internalForwardInfo
 316  
                                 .getInternalForwardPath();
 317  0
                 final MockHttpServletRequest internalForwardRequest = this
 318  
                                 .getServletContext().createRequest(internalForwardPath);
 319  0
                 final MockHttpServletRequest request = getRequest();
 320  0
                 request.setAttribute(ATTR_ROUTINGS, internalForwardInfo
 321  
                                 .getOnSubmitRoutings());
 322  0
                 Beans.copy(internalForwardRequest, request).execute();
 323  0
                 final Field servletPathField = ClassUtil.getDeclaredField(request
 324  
                                 .getClass(), "servletPath");
 325  0
                 servletPathField.setAccessible(true);
 326  
                 try {
 327  0
                         servletPathField.set(request, internalForwardRequest
 328  
                                         .getServletPath());
 329  0
                 } catch (final Exception ex) {
 330  0
                         throw new RuntimeException(ex);
 331  0
                 }
 332  0
                 request.setQueryString(internalForwardRequest.getQueryString());
 333  0
                 if (StringUtil.isNotBlank(internalForwardRequest.getQueryString())) {
 334  0
                         request.getParameterMap().putAll(
 335  
                                         javax.servlet.http.HttpUtils.parseQueryString(request
 336  
                                                         .getQueryString()));
 337  
                 }
 338  0
                 return internalForwardPath;
 339  
         }
 340  
 
 341  
 }