Support multiple service models for a component. WindsorServiceHostFactory will...
[castle.git] / MonoRail / Castle.MonoRail.TestSupport / BaseControllerTest.cs
bloba3e2059b31de300135f215bcd44df1c430d5f8d4
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 protected void PrepareController(Controller controller, string controllerName)
234 PrepareController(controller, controllerName, "Action");
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="controllerName">Name of the controller.</param>
244 /// <param name="actionName">Name of the action.</param>
245 protected void PrepareController(Controller controller, string controllerName, string actionName)
247 PrepareController(controller, "", controllerName, actionName);
250 /// <summary>
251 /// Prepares the controller giving it mock implementations
252 /// of the service it requires to function normally.
253 /// </summary>
254 /// <param name="controller">The controller.</param>
255 /// <param name="areaName">Name of the area (cannot be null).</param>
256 /// <param name="controllerName">Name of the controller.</param>
257 /// <param name="actionName">Name of the action.</param>
258 protected void PrepareController(Controller controller, string areaName, string controllerName, string actionName)
260 PrepareController(controller, areaName, controllerName, actionName, InitializeEngineContext);
263 /// <summary>
264 /// Prepares the controller giving it mock implementations
265 /// of the service it requires to function normally.
266 /// </summary>
267 /// <param name="controller">The controller.</param>
268 /// <param name="areaName">Name of the area (cannot be null).</param>
269 /// <param name="controllerName">Name of the controller.</param>
270 /// <param name="actionName">Name of the action.</param>
271 /// <param name="contextInitializer">The context initializer.</param>
272 protected void PrepareController(Controller controller, string areaName, string controllerName, string actionName, ContextInitializer contextInitializer)
274 if (controller == null)
276 throw new ArgumentNullException("controller", "'controller' cannot be null");
278 if (areaName == null)
280 throw new ArgumentNullException("areaName");
282 if (controllerName == null)
284 throw new ArgumentNullException("controllerName");
286 if (actionName == null)
288 throw new ArgumentNullException("actionName");
291 cookies = new Dictionary<string, HttpCookie>(StringComparer.InvariantCultureIgnoreCase);
293 BuildEngineContext(areaName, controllerName, actionName, contextInitializer);
295 controllerContext = services.ControllerContextFactory.Create(areaName, controllerName, actionName, services.ControllerDescriptorProvider.BuildDescriptor(controller));
297 controller.Contextualize(Context, controllerContext);
298 controller.CreateStandardHelpers();
300 controller.Initialize();
303 /// <summary>
304 /// Constructs a mock context.
305 /// </summary>
306 /// <param name="areaName">Name of the area.</param>
307 /// <param name="controllerName">Name of the controller.</param>
308 /// <param name="actionName">Name of the action.</param>
309 protected void BuildEngineContext(string areaName, string controllerName, string actionName)
311 BuildEngineContext(areaName, controllerName, actionName, InitializeEngineContext);
314 /// <summary>
315 /// Constructs a mock context.
316 /// </summary>
317 /// <param name="areaName">Name of the area.</param>
318 /// <param name="controllerName">Name of the controller.</param>
319 /// <param name="actionName">Name of the action.</param>
320 /// <param name="contextInitializer">The context initializer.</param>
321 protected void BuildEngineContext(string areaName, string controllerName, string actionName, ContextInitializer contextInitializer)
323 UrlInfo info = BuildUrlInfo(areaName, controllerName, actionName);
324 services = BuildServices();
325 request = BuildRequest();
326 response = BuildResponse(info);
327 trace = BuildTrace();
328 context = BuildRailsEngineContext(request, response, services, trace, info);
329 contextInitializer(context);
332 /// <summary>
333 /// Builds the request.
334 /// </summary>
335 /// <returns></returns>
336 protected virtual IMockRequest BuildRequest()
338 return new MockRequest(cookies);
341 /// <summary>
342 /// Builds the services.
343 /// </summary>
344 /// <returns></returns>
345 protected virtual MockServices BuildServices()
347 return new MockServices();
350 /// <summary>
351 /// Builds the response.
352 /// </summary>
353 /// <returns></returns>
354 protected virtual IMockResponse BuildResponse(UrlInfo info)
356 return new MockResponse(cookies, info);
359 /// <summary>
360 /// Builds the trace.
361 /// </summary>
362 /// <returns></returns>
363 protected virtual ITrace BuildTrace()
365 return new MockTrace();
368 /// <summary>
369 /// Builds the a mock context. You can override this method to
370 /// create a special configured mock context.
371 /// </summary>
372 /// <param name="request">The request.</param>
373 /// <param name="response">The response.</param>
374 /// <param name="services">The services.</param>
375 /// <param name="trace">The trace.</param>
376 /// <param name="urlInfo">The URL info.</param>
377 /// <returns></returns>
378 protected virtual MockEngineContext BuildRailsEngineContext(IMockRequest request, IMockResponse response,
379 IMonoRailServices services, ITrace trace, UrlInfo urlInfo)
381 MockEngineContext engine = new MockEngineContext(request, response, services, urlInfo);
382 engine.Trace = trace;
383 return engine;
386 /// <summary>
387 /// Builds the URL info that represents the contextual Url.
388 /// </summary>
389 /// <param name="areaName">Name of the area.</param>
390 /// <param name="controllerName">Name of the controller.</param>
391 /// <param name="actionName">Name of the action.</param>
392 /// <returns></returns>
393 protected virtual UrlInfo BuildUrlInfo(string areaName, string controllerName, string actionName)
395 return new UrlInfo(domain, domainPrefix, virtualDir, "http", port,
396 Path.Combine(Path.Combine(areaName, controllerName), actionName),
397 areaName, controllerName, actionName, ".castle", null);
400 /// <summary>
401 /// Allows modifying of the engine context created by <see cref="BuildRailsEngineContext"/>
402 /// </summary>
403 /// <param name="mockEngineContext">The engine context to modify</param>
404 protected virtual void InitializeEngineContext(MockEngineContext mockEngineContext)
407 /// <summary>
408 /// Determines whether a specified template was rendered -- to send an email.
409 /// </summary>
410 /// <param name="templateName">Name of the template.</param>
411 /// <returns>
412 /// <c>true</c> if was rendered; otherwise, <c>false</c>.
413 /// </returns>
414 protected bool HasRenderedEmailTemplateNamed(string templateName)
416 MockEngineContext.RenderedEmailTemplate template =
417 context.RenderedEmailTemplates.Find(
418 delegate(MockEngineContext.RenderedEmailTemplate emailTemplate)
420 return templateName.Equals(emailTemplate.Name, StringComparison.OrdinalIgnoreCase);
423 return template != null;
426 /// <summary>
427 /// Gets the fake email messages sent.
428 /// </summary>
429 /// <value>The messages sent.</value>
430 protected Message[] MessagesSent
432 get { return context.MessagesSent.ToArray(); }
435 /// <summary>
436 /// Gets the rendered email templates.
437 /// </summary>
438 /// <value>The rendered email templates.</value>
439 protected MockEngineContext.RenderedEmailTemplate[] RenderedEmailTemplates
441 get { return context.RenderedEmailTemplates.ToArray(); }