1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.MonoRail
.TestSupport
18 using System
.Collections
;
19 using System
.Collections
.Specialized
;
21 using Castle
.Components
.Common
.EmailSender
;
22 using Castle
.MonoRail
.Framework
;
23 using Castle
.MonoRail
.Framework
.Test
;
25 public delegate void ContextInitializer(MockRailsEngineContext context
);
28 /// Base class that set ups the necessary infrastructure
29 /// to test controllers without the need
30 /// for an ASP.Net Runtime.
34 /// The following code is an example of a controller test:
38 /// public class LoginControllerTestCase : BaseControllerTest
40 /// private LoginController controller;
43 /// public void Init()
45 /// controller = new LoginController();
46 /// PrepareController(controller);
50 /// public void Authenticate_Should_Use_The_AuthenticationService()
52 /// // set up a mock authentication service before
54 /// controller.Authenticate("username", "my password", false);
56 /// Assert.AreEqual(3, controller.PropertyBag.Count);
57 /// Assert.AreEqual("username", controller.PropertyBag["username"]);
58 /// Assert.AreEqual("my password", controller.PropertyBag["password"]);
59 /// Assert.AreEqual(false, controller.PropertyBag["autoLogin"]);
65 /// The following is a more sophisticate test for an action that sends emails.
70 /// public void Register_Should_Add_Registration_Using_The_Repository()
72 /// Registration reg = new Registration("John Doe", "johndoe@gmail.com");
74 /// using(mockRepository.Record())
76 /// registrationRepositoryMock.Add(reg);
79 /// using(mockRepository.Playback())
81 /// controller.Register(reg); // This action sends two emails
83 /// Assert.IsTrue(HasRenderedEmailTemplateNamed("emailToManager"));
84 /// Assert.IsTrue(HasRenderedEmailTemplateNamed("emailToParticipant"));
86 /// Assert.AreEqual("manager@gmail.com", MessagesSent[0].To);
87 /// Assert.AreEqual("johndoe@gmail.com", MessagesSent[1].To);
89 /// Assert.AreEqual("Registration\\Success", controller.SelectedViewName);
97 /// You must invoke <see cref="PrepareController(Controller)"/> -- or a different overload -
98 /// before making invocations to the controller.
100 public abstract class BaseControllerTest
102 private readonly string domain
;
103 private readonly string domainPrefix
;
104 private readonly int port
;
105 protected string virtualDir
= "";
106 private MockRailsEngineContext context
;
107 private IMockRequest request
;
108 private IMockResponse response
;
109 private ITrace trace
;
110 private IDictionary cookies
;
113 /// Initializes a new instance of the <see cref="BaseControllerTest"/> class.
115 protected BaseControllerTest() : this("app.com", "www", 80)
120 /// Initializes a new instance of the <see cref="BaseControllerTest"/> class.
122 /// <param name="domain">The domain.</param>
123 /// <param name="domainPrefix">The domain prefix.</param>
124 /// <param name="port">The port.</param>
125 protected BaseControllerTest(string domain
, string domainPrefix
, int port
)
127 this.domain
= domain
;
128 this.domainPrefix
= domainPrefix
;
133 /// Override to perform any pre-test set up
135 protected virtual void OnSetUp()
140 /// Gets the cookies.
142 /// <value>The cookies.</value>
143 public IDictionary Cookies
145 get { return cookies; }
149 /// Gets the context.
151 /// <value>The context.</value>
152 protected IRailsEngineContext Context
154 get { return context; }
158 /// Gets the request.
160 /// <value>The request.</value>
161 public IMockRequest Request
163 get { return request; }
167 /// Gets the response.
169 /// <value>The response.</value>
170 public IMockResponse Response
172 get { return response; }
178 /// <value>The trace.</value>
181 get { return trace; }
185 /// Prepares the controller giving it mock implementations
186 /// of the service it requires to function normally.
188 /// <param name="controller">The controller.</param>
189 protected void PrepareController(Controller controller
)
191 PrepareController(controller
, InitializeRailsEngineContext
);
195 /// Prepares the controller giving it mock implementations
196 /// of the service it requires to function normally.
198 /// <param name="controller">The controller.</param>
199 /// <param name="contextInitializer">The context initializer.</param>
200 protected void PrepareController(Controller controller
, ContextInitializer contextInitializer
)
202 PrepareController(controller
, "", "Controller", "Action", contextInitializer
);
206 /// Prepares the controller giving it mock implementations
207 /// of the service it requires to function normally.
209 /// <param name="controller">The controller.</param>
210 /// <param name="controllerName">Name of the controller.</param>
211 /// <param name="actionName">Name of the action.</param>
212 protected void PrepareController(Controller controller
, string controllerName
, string actionName
)
214 PrepareController(controller
, "", controllerName
, actionName
);
218 /// Prepares the controller giving it mock implementations
219 /// of the service it requires to function normally.
221 /// <param name="controller">The controller.</param>
222 /// <param name="areaName">Name of the area (cannot be null).</param>
223 /// <param name="controllerName">Name of the controller.</param>
224 /// <param name="actionName">Name of the action.</param>
225 protected void PrepareController(Controller controller
, string areaName
, string controllerName
, string actionName
)
227 PrepareController(controller
, areaName
, controllerName
, actionName
, InitializeRailsEngineContext
);
231 /// Prepares the controller giving it mock implementations
232 /// of the service it requires to function normally.
234 /// <param name="controller">The controller.</param>
235 /// <param name="areaName">Name of the area (cannot be null).</param>
236 /// <param name="controllerName">Name of the controller.</param>
237 /// <param name="actionName">Name of the action.</param>
238 /// <param name="contextInitializer">The context initializer.</param>
239 protected void PrepareController(Controller controller
, string areaName
, string controllerName
, string actionName
, ContextInitializer contextInitializer
)
241 if (controller
== null)
243 throw new ArgumentNullException("controller", "'controller' cannot be null");
245 if (areaName
== null)
247 throw new ArgumentNullException("areaName");
249 if (controllerName
== null)
251 throw new ArgumentNullException("controllerName");
253 if (actionName
== null)
255 throw new ArgumentNullException("actionName");
257 if( contextInitializer
== null) {
258 throw new ArgumentNullException("contextInitializer");
261 cookies
= new HybridDictionary(true);
263 BuildRailsContext(areaName
, controllerName
, actionName
, contextInitializer
);
264 controller
.InitializeFieldsFromServiceProvider(context
);
265 controller
.InitializeControllerState(areaName
, controllerName
, actionName
);
266 ControllerLifecycleExecutor executor
= new ControllerLifecycleExecutor(controller
, context
);
267 executor
.Service(context
);
268 executor
.InitializeController(controller
.AreaName
, controller
.Name
, controller
.Action
);
272 /// Constructs a mock context.
274 /// <param name="areaName">Name of the area.</param>
275 /// <param name="controllerName">Name of the controller.</param>
276 /// <param name="actionName">Name of the action.</param>
277 protected void BuildRailsContext(string areaName
, string controllerName
, string actionName
)
279 BuildRailsContext(areaName
, controllerName
, actionName
, InitializeRailsEngineContext
);
283 /// Constructs a mock context.
285 /// <param name="areaName">Name of the area.</param>
286 /// <param name="controllerName">Name of the controller.</param>
287 /// <param name="actionName">Name of the action.</param>
288 /// <param name="contextInitializer">The context initializer.</param>
289 protected void BuildRailsContext(string areaName
, string controllerName
, string actionName
, ContextInitializer contextInitializer
)
291 UrlInfo info
= BuildUrlInfo(areaName
, controllerName
, actionName
);
292 request
= BuildRequest();
293 response
= BuildResponse();
294 trace
= BuildTrace();
295 context
= BuildRailsEngineContext(request
, response
, trace
, info
);
296 contextInitializer(context
);
300 /// Builds the request.
302 /// <returns></returns>
303 protected virtual IMockRequest
BuildRequest()
305 return new MockRequest(cookies
);
309 /// Builds the response.
311 /// <returns></returns>
312 protected virtual IMockResponse
BuildResponse()
314 return new MockResponse(cookies
);
318 /// Builds the trace.
320 /// <returns></returns>
321 protected virtual ITrace
BuildTrace()
323 return new MockTrace();
327 /// Builds the a mock context. You can override this method to
328 /// create a special configured mock context.
330 /// <param name="request">The request.</param>
331 /// <param name="response">The response.</param>
332 /// <param name="trace">The trace.</param>
333 /// <param name="urlInfo">The URL info.</param>
334 /// <returns></returns>
335 protected virtual MockRailsEngineContext
BuildRailsEngineContext(IRequest request
, IResponse response
, ITrace trace
,
338 return new MockRailsEngineContext(request
, response
, trace
, urlInfo
);
342 /// Builds the URL info that represents the contextual Url.
344 /// <param name="areaName">Name of the area.</param>
345 /// <param name="controllerName">Name of the controller.</param>
346 /// <param name="actionName">Name of the action.</param>
347 /// <returns></returns>
348 protected virtual UrlInfo
BuildUrlInfo(string areaName
, string controllerName
, string actionName
)
350 return new UrlInfo(domain
, domainPrefix
, virtualDir
, "http", port
,
351 Path
.Combine(Path
.Combine(areaName
, controllerName
), actionName
),
352 areaName
, controllerName
, actionName
, "rails", null);
356 /// Allows modifying of the engine context created by <see cref="BuildRailsEngineContext"/>
358 /// <param name="mockRailsEngineContext">The engine context to modify</param>
359 protected virtual void InitializeRailsEngineContext(MockRailsEngineContext mockRailsEngineContext
)
363 /// Determines whether a specified template was rendered -- to send an email.
365 /// <param name="templateName">Name of the template.</param>
367 /// <c>true</c> if was rendered; otherwise, <c>false</c>.
369 protected bool HasRenderedEmailTemplateNamed(string templateName
)
371 MockRailsEngineContext
.RenderedEmailTemplate template
=
372 context
.RenderedEmailTemplates
.Find(
373 delegate(MockRailsEngineContext
.RenderedEmailTemplate emailTemplate
)
375 return templateName
.Equals(emailTemplate
.Name
, StringComparison
.OrdinalIgnoreCase
);
378 return template
!= null;
382 /// Gets the fake email messages sent.
384 /// <value>The messages sent.</value>
385 protected Message
[] MessagesSent
387 get { return context.MessagesSent.ToArray(); }
391 /// Gets the rendered email templates.
393 /// <value>The rendered email templates.</value>
394 protected MockRailsEngineContext
.RenderedEmailTemplate
[] RenderedEmailTemplates
396 get { return context.RenderedEmailTemplates.ToArray(); }