View Javadoc

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 java.io.IOException;
19  import java.lang.reflect.Field;
20  
21  import javax.servlet.FilterChain;
22  import javax.servlet.ServletException;
23  import javax.servlet.ServletRequest;
24  import javax.servlet.ServletResponse;
25  
26  import org.seasar.cubby.action.ActionResult;
27  import org.seasar.cubby.action.Forward;
28  import org.seasar.cubby.action.Redirect;
29  import org.seasar.cubby.controller.ActionProcessor;
30  import org.seasar.cubby.routing.InternalForwardInfo;
31  import org.seasar.cubby.routing.Router;
32  import org.seasar.framework.beans.util.Beans;
33  import org.seasar.framework.mock.servlet.MockHttpServletRequest;
34  import org.seasar.framework.mock.servlet.MockHttpServletResponse;
35  import org.seasar.framework.unit.S2TigerTestCase;
36  import org.seasar.framework.util.ClassUtil;
37  import org.seasar.framework.util.StringUtil;
38  
39  /**
40   * CubbyのActionクラスの単体テスト用のクラスです。
41   * <p>
42   * このクラスを継承して、それぞれのActionクラス用の単体テストを作成します。 詳細はCubbyドキュメントの「アクションのテスト」を参照下さい。
43   * 
44   * <pre>
45   * public class HelloActionTest extends CubbyTestCase {
46   * 	// 対象のアクション
47   * 	private HelloAction action;
48   * 
49   * 	// 初期化処理
50   * 	protected void setUp() throws Exception {
51   * 		// diconファイルの読み込み
52   * 		include(&quot;app.dicon&quot;);
53   * 	}
54   * 
55   * 	public void testIndex() throws Exception {
56   * 		// アクションの実行
57   * 		ActionResult result = processAction(&quot;/hello/&quot;);
58   * 		// 結果のチェック
59   * 		assertPathEquals(Forward.class, &quot;input.jsp&quot;, result);
60   * 	}
61   * 
62   * 	public void testMessage() throws Exception {
63   * 		// リクエストパラメータのセット
64   * 		getRequest().addParameter(&quot;name&quot;, &quot;name1&quot;);
65   * 		// アクションの実行
66   * 		ActionResult result = processAction(&quot;/hello/message&quot;);
67   * 		// 結果のチェック
68   * 		assertPathEquals(Forward.class, &quot;result.jsp&quot;, result);
69   * 		// 実行後のアクションの状態を確認
70   * 		assertEquals(&quot;name1&quot;, action.name);
71   * 	}
72   * }
73   * </pre>
74   * 
75   * <pre>
76   * public class TodoActionTest extends CubbyTestCase {
77   * 	private TodoAction action;
78   * 
79   * 	protected void setUp() throws Exception {
80   * 		include(&quot;app.dicon&quot;);
81   * 		RunDdlServletRequestListener listener = new RunDdlServletRequestListener();
82   * 		listener.requestInitialized(null);
83   * 	}
84   * 
85   * 	&#064;Override
86   * 	protected void setUpAfterBindFields() throws Throwable {
87   * 		super.setUpAfterBindFields();
88   * 		getRequest().addParameter(&quot;userId&quot;, &quot;test&quot;);
89   * 		getRequest().addParameter(&quot;password&quot;, &quot;test&quot;);
90   * 		// 後続のテストを実行するためにログインアクションを実行
91   * 		assertPathEquals(Redirect.class, &quot;/todo/&quot;,
92   * 				processAction(&quot;/todo/login/process&quot;));
93   * 	}
94   * 
95   * 	public void testShow() throws Exception {
96   * 		this.readXlsAllReplaceDb(&quot;TodoActionTest_PREPARE.xls&quot;);
97   * 		// CoolURIの場合のテスト
98   * 		ActionResult result = processAction(&quot;/todo/1&quot;);
99   * 		assertPathEquals(Forward.class, &quot;show.jsp&quot;, result);
100  * 		assertEquals(new Integer(1), action.id);
101  * 		assertEquals(&quot;todo1&quot;, action.text);
102  * 		assertEquals(&quot;todo1 memo&quot;, action.memo);
103  * 		assertEquals(new Integer(1), action.todoType.getId());
104  * 		assertEquals(&quot;type1&quot;, action.todoType.getName());
105  * 		assertEquals(&quot;2008-01-01&quot;, action.limitDate);
106  * 	}
107  * }
108  * </pre>
109  * 
110  * </p>
111  * 
112  * @author agata
113  * @author baba
114  * @since 1.0.0
115  */
116 public abstract class CubbyTestCase extends S2TigerTestCase {
117 
118 	/** ルーティング */
119 	private Router router;
120 
121 	/** フィルターチェイン */
122 	private final MockFilterChain filterChain = new MockFilterChain();
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 		assertEquals("ActionResultの型をチェック", resultClass, actualResult
141 				.getClass());
142 		if (actualResult instanceof Forward) {
143 			assertEquals("パスのチェック", expectedPath, ((Forward) actualResult)
144 					.getPath());
145 		} else if (actualResult instanceof Redirect) {
146 			assertEquals("パスのチェック", expectedPath, ((Redirect) actualResult)
147 					.getPath());
148 		}
149 	}
150 
151 	/**
152 	 * アクションメソッドを実行します。
153 	 * 
154 	 * @param orginalPath
155 	 *            パス
156 	 * @return アクションメソッドの実行結果。アクションメソッドが見つからなかったり結果がない場合、null
157 	 * @throws Exception
158 	 */
159 	protected ActionResult processAction(final String orginalPath)
160 			throws Exception {
161 		routing(orginalPath);
162 		return actionProcessor
163 				.process(getRequest(), getResponse(), filterChain);
164 	}
165 
166 	/**
167 	 * CubbyFilterで行っているルーティングをエミュレートして、内部フォワードパスをリクエストにセットします。
168 	 * 
169 	 * @param orginalPath
170 	 *            オリジナルパス
171 	 * @return 内部フォワードパス
172 	 */
173 	@SuppressWarnings( { "unchecked", "deprecation" })
174 	protected String routing(final String orginalPath) {
175 		final MockHttpServletRequest request = this.getServletContext()
176 				.createRequest(orginalPath);
177 		final MockHttpServletResponse response = this.getResponse();
178 		final InternalForwardInfo internalForwardInfo = router.routing(request,
179 				response);
180 		if (internalForwardInfo == null) {
181 			fail(orginalPath + " could not mapping to action");
182 		}
183 		final String internalForwardPath = internalForwardInfo
184 				.getInternalForwardPath();
185 		final MockHttpServletRequest internalForwardRequest = this
186 				.getServletContext().createRequest(internalForwardPath);
187 		Beans.copy(internalForwardRequest, getRequest()).execute();
188 		final Field servletPathField = ClassUtil.getDeclaredField(getRequest()
189 				.getClass(), "servletPath");
190 		servletPathField.setAccessible(true);
191 		try {
192 			servletPathField.set(getRequest(), internalForwardRequest
193 					.getServletPath());
194 		} catch (final Exception ex) {
195 			throw new RuntimeException(ex);
196 		}
197 
198 		if (StringUtil.isNotBlank(internalForwardRequest.getQueryString())) {
199 			getRequest().getParameterMap().putAll(
200 					javax.servlet.http.HttpUtils.parseQueryString(getRequest()
201 							.getQueryString()));
202 		}
203 		return internalForwardPath;
204 	}
205 
206 	/**
207 	 * モックのFilterChain。
208 	 * 
209 	 * @author agata
210 	 */
211 	private static class MockFilterChain implements FilterChain {
212 		/**
213 		 * {@inheritDoc}
214 		 */
215 		public void doFilter(final ServletRequest request,
216 				final ServletResponse response) throws IOException,
217 				ServletException {
218 		}
219 	}
220 
221 }