- CheckboxList's LabelFor now takes attributes as optional argument
[castle.git] / MonoRail / Castle.MonoRail.TestSupport / BaseControllerTest.cs
blobc7be1a9e5b021880767a8b9491636a19a4f1732f
1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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
17 using System;
18 using System.Collections.Generic;
19 using System.Collections.Specialized;
20 using System.IO;
21 using System.Web;
22 using Castle.Components.Common.EmailSender;
23 using Castle.MonoRail.Framework;
24 using Castle.MonoRail.Framework.Test;
26 public delegate void ContextInitializer(MockEngineContext context);
28 /// <summary>
29 /// Base class that set ups the necessary infrastructure
30 /// to test controllers without the need
31 /// for an ASP.Net Runtime.
32 /// </summary>
33 ///
34 /// <example>
35 /// The following code is an example of a controller test:
36 ///
37 /// <code lang="cs">
38 /// [TestFixture]
39 /// public class LoginControllerTestCase : BaseControllerTest
40 /// {
41 /// private LoginController controller;
42 ///
43 /// [SetUp]
44 /// public void Init()
45 /// {
46 /// controller = new LoginController();
47 /// PrepareController(controller);
48 /// }
49 ///
50 /// [Test]
51 /// public void Authenticate_Should_Use_The_AuthenticationService()
52 /// {
53 /// // set up a mock authentication service before
54 ///
55 /// controller.Authenticate("username", "my password", false);
56 ///
57 /// Assert.AreEqual(3, controller.PropertyBag.Count);
58 /// Assert.AreEqual("username", controller.PropertyBag["username"]);
59 /// Assert.AreEqual("my password", controller.PropertyBag["password"]);
60 /// Assert.AreEqual(false, controller.PropertyBag["autoLogin"]);
61 /// }
62 /// }
63 /// </code>
64 ///
65 /// <para>
66 /// The following is a more sophisticate test for an action that sends emails.
67 /// </para>
68 ///
69 /// <code lang="cs">
70 /// [Test]
71 /// public void Register_Should_Add_Registration_Using_The_Repository()
72 /// {
73 /// Registration reg = new Registration("John Doe", "johndoe@gmail.com");
74 ///
75 /// using(mockRepository.Record())
76 /// {
77 /// registrationRepositoryMock.Add(reg);
78 /// }
79 ///
80 /// using(mockRepository.Playback())
81 /// {
82 /// controller.Register(reg); // This action sends two emails
83 ///
84 /// Assert.IsTrue(HasRenderedEmailTemplateNamed("emailToManager"));
85 /// Assert.IsTrue(HasRenderedEmailTemplateNamed("emailToParticipant"));
86 ///
87 /// Assert.AreEqual("manager@gmail.com", MessagesSent[0].To);
88 /// Assert.AreEqual("johndoe@gmail.com", MessagesSent[1].To);
89 ///
90 /// Assert.AreEqual("Registration\\Success", controller.SelectedViewName);
91 /// }
92 /// }
93 /// </code>
94 ///
95 /// </example>
96 ///
97 /// <remarks>
98 /// You must invoke <see cref="PrepareController(Controller)"/> -- or a different overload -
99 /// before making invocations to the controller.
100 /// </remarks>
101 public abstract class BaseControllerTest
103 private readonly string domain;
104 private readonly string domainPrefix;
105 private readonly int port;
106 private MockEngineContext context;
107 private IMockRequest request;
108 private IMockResponse response;
109 private MockServices services;
110 private ITrace trace;
111 private IDictionary<string, HttpCookie> cookies;
112 private IControllerContext controllerContext;
113 protected string virtualDir = "";
115 /// <summary>
116 /// Initializes a new instance of the <see cref="BaseControllerTest"/> class.
117 /// </summary>
118 protected BaseControllerTest() : this("app.com", "www", 80)
122 /// <summary>
123 /// Initializes a new instance of the <see cref="BaseControllerTest"/> class.
124 /// </summary>
125 /// <param name="domain">The domain.</param>
126 /// <param name="domainPrefix">The domain prefix.</param>
127 /// <param name="port">The port.</param>
128 protected BaseControllerTest(string domain, string domainPrefix, int port)
130 this.domain = domain;
131 this.domainPrefix = domainPrefix;
132 this.port = port;
135 /// <summary>
136 /// Override to perform any pre-test set up
137 /// </summary>
138 protected virtual void OnSetUp()
142 /// <summary>
143 /// Gets the cookies.
144 /// </summary>
145 /// <value>The cookies.</value>
146 public IDictionary<string, HttpCookie> Cookies
148 get { return cookies; }
151 /// <summary>
152 /// Gets the context.
153 /// </summary>
154 /// <value>The context.</value>
155 protected IEngineContext Context
157 get { return context; }
160 /// <summary>
161 /// Gets the request.
162 /// </summary>
163 /// <value>The request.</value>
164 public IMockRequest Request
166 get { return request; }
169 /// <summary>
170 /// Gets the response.
171 /// </summary>
172 /// <value>The response.</value>
173 public IMockResponse Response
175 get { return response; }
178 /// <summary>
179 /// Gets the trace.
180 /// </summary>
181 /// <value>The trace.</value>
182 public ITrace Trace
184 get { return trace; }
187 /// <summary>
188 /// Gets the controller context.
189 /// </summary>
190 /// <value>The controller context.</value>
191 public IControllerContext ControllerContext
193 get { return controllerContext; }
196 /// <summary>
197 /// Gets the services.
198 /// </summary>
199 /// <value>The services.</value>
200 public MockServices Services
202 get { return services; }
205 /// <summary>
206 /// Prepares the controller giving it mock implementations
207 /// of the service it requires to function normally.
208 /// </summary>
209 /// <param name="controller">The controller.</param>
210 protected void PrepareController(Controller controller)
212 PrepareController(controller, InitializeEngineContext);
215 /// <summary>
216 /// Prepares the controller giving it mock implementations
217 /// of the service it requires to function normally.
218 /// </summary>
219 /// <param name="controller">The controller.</param>
220 /// <param name="contextInitializer">The context initializer.</param>
221 protected void PrepareController(Controller controller, ContextInitializer contextInitializer)
223 PrepareController(controller, "", "Controller", "Action", contextInitializer);
226 /// <summary>
227 /// Prepares the controller giving it mock implementations
228 /// of the service it requires to function normally.
229 /// </summary>
230 /// <param name="controller">The controller.</param>
231 /// <param name="controllerName">Name of the controller.</param>
232 /// <param name="actionName">Name of the action.</param>
233 protected void PrepareController(Controller controller, string controllerName, string actionName)
235 PrepareController(controller, "", controllerName, actionName);
238 /// <summary>
239 /// Prepares the controller giving it mock implementations
240 /// of the service it requires to function normally.
241 /// </summary>
242 /// <param name="controller">The controller.</param>
243 /// <param name="areaName">Name of the area (cannot be null).</param>
244 /// <param name="controllerName">Name of the controller.</param>
245 /// <param name="actionName">Name of the action.</param>
246 protected void PrepareController(Controller controller, string areaName, string controllerName, string actionName)
248 PrepareController(controller, areaName, controllerName, actionName, InitializeEngineContext);
251 /// <summary>
252 /// Prepares the controller giving it mock implementations
253 /// of the service it requires to function normally.
254 /// </summary>
255 /// <param name="controller">The controller.</param>
256 /// <param name="areaName">Name of the area (cannot be null).</param>
257 /// <param name="controllerName">Name of the controller.</param>
258 /// <param name="actionName">Name of the action.</param>
259 /// <param name="contextInitializer">The context initializer.</param>
260 protected void PrepareController(Controller controller, string areaName, string controllerName, string actionName, ContextInitializer contextInitializer)
262 if (controller == null)
264 throw new ArgumentNullException("controller", "'controller' cannot be null");
266 if (areaName == null)
268 throw new ArgumentNullException("areaName");
270 if (controllerName == null)
272 throw new ArgumentNullException("controllerName");
274 if (actionName == null)
276 throw new ArgumentNullException("actionName");
279 cookies = new Dictionary<string, HttpCookie>(StringComparer.InvariantCultureIgnoreCase);
281 BuildEngineContext(areaName, controllerName, actionName, contextInitializer);
283 controllerContext = services.ControllerContextFactory.Create(areaName, controllerName, actionName, services.ControllerDescriptorProvider.BuildDescriptor(controller));
285 controller.SetEngineContext(Context);
286 controller.ControllerContext = controllerContext;
287 controller.CreateStandardHelpers();
290 /// <summary>
291 /// Constructs a mock context.
292 /// </summary>
293 /// <param name="areaName">Name of the area.</param>
294 /// <param name="controllerName">Name of the controller.</param>
295 /// <param name="actionName">Name of the action.</param>
296 protected void BuildEngineContext(string areaName, string controllerName, string actionName)
298 BuildEngineContext(areaName, controllerName, actionName, InitializeEngineContext);
301 /// <summary>
302 /// Constructs a mock context.
303 /// </summary>
304 /// <param name="areaName">Name of the area.</param>
305 /// <param name="controllerName">Name of the controller.</param>
306 /// <param name="actionName">Name of the action.</param>
307 /// <param name="contextInitializer">The context initializer.</param>
308 protected void BuildEngineContext(string areaName, string controllerName, string actionName, ContextInitializer contextInitializer)
310 UrlInfo info = BuildUrlInfo(areaName, controllerName, actionName);
311 services = BuildServices();
312 request = BuildRequest();
313 response = BuildResponse();
314 trace = BuildTrace();
315 context = BuildRailsEngineContext(request, response, services, trace, info);
316 contextInitializer(context);
319 /// <summary>
320 /// Builds the request.
321 /// </summary>
322 /// <returns></returns>
323 protected virtual IMockRequest BuildRequest()
325 return new MockRequest(cookies);
328 /// <summary>
329 /// Builds the services.
330 /// </summary>
331 /// <returns></returns>
332 protected virtual MockServices BuildServices()
334 return new MockServices();
337 /// <summary>
338 /// Builds the response.
339 /// </summary>
340 /// <returns></returns>
341 protected virtual IMockResponse BuildResponse()
343 return new MockResponse(cookies);
346 /// <summary>
347 /// Builds the trace.
348 /// </summary>
349 /// <returns></returns>
350 protected virtual ITrace BuildTrace()
352 return new MockTrace();
355 /// <summary>
356 /// Builds the a mock context. You can override this method to
357 /// create a special configured mock context.
358 /// </summary>
359 /// <param name="request">The request.</param>
360 /// <param name="response">The response.</param>
361 /// <param name="services">The services.</param>
362 /// <param name="trace">The trace.</param>
363 /// <param name="urlInfo">The URL info.</param>
364 /// <returns></returns>
365 protected virtual MockEngineContext BuildRailsEngineContext(IMockRequest request, IMockResponse response,
366 IMonoRailServices services, ITrace trace, UrlInfo urlInfo)
368 MockEngineContext engine = new MockEngineContext(request, response, services, urlInfo);
369 engine.Trace = trace;
370 return engine;
373 /// <summary>
374 /// Builds the URL info that represents the contextual Url.
375 /// </summary>
376 /// <param name="areaName">Name of the area.</param>
377 /// <param name="controllerName">Name of the controller.</param>
378 /// <param name="actionName">Name of the action.</param>
379 /// <returns></returns>
380 protected virtual UrlInfo BuildUrlInfo(string areaName, string controllerName, string actionName)
382 return new UrlInfo(domain, domainPrefix, virtualDir, "http", port,
383 Path.Combine(Path.Combine(areaName, controllerName), actionName),
384 areaName, controllerName, actionName, "rails", null);
387 /// <summary>
388 /// Allows modifying of the engine context created by <see cref="BuildRailsEngineContext"/>
389 /// </summary>
390 /// <param name="mockEngineContext">The engine context to modify</param>
391 protected virtual void InitializeEngineContext(MockEngineContext mockEngineContext)
394 /// <summary>
395 /// Determines whether a specified template was rendered -- to send an email.
396 /// </summary>
397 /// <param name="templateName">Name of the template.</param>
398 /// <returns>
399 /// <c>true</c> if was rendered; otherwise, <c>false</c>.
400 /// </returns>
401 protected bool HasRenderedEmailTemplateNamed(string templateName)
403 MockEngineContext.RenderedEmailTemplate template =
404 context.RenderedEmailTemplates.Find(
405 delegate(MockEngineContext.RenderedEmailTemplate emailTemplate)
407 return templateName.Equals(emailTemplate.Name, StringComparison.OrdinalIgnoreCase);
410 return template != null;
413 /// <summary>
414 /// Gets the fake email messages sent.
415 /// </summary>
416 /// <value>The messages sent.</value>
417 protected Message[] MessagesSent
419 get { return context.MessagesSent.ToArray(); }
422 /// <summary>
423 /// Gets the rendered email templates.
424 /// </summary>
425 /// <value>The rendered email templates.</value>
426 protected MockEngineContext.RenderedEmailTemplate[] RenderedEmailTemplates
428 get { return context.RenderedEmailTemplates.ToArray(); }