Skip to content

Commit 127b37a

Browse files
committed
Finished readme
1 parent e3179db commit 127b37a

1 file changed

Lines changed: 136 additions & 4 deletions

File tree

README.md

Lines changed: 136 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ If you are redirecting to an action that takes no parameters, or takes a single
9999

100100
Then you can write this test:
101101

102-
_controller.WithCallTo(c => c.RedirectToActionWithNoParameters()).ShouldRedirectTo(c => c.ActionWithNoParameters)
102+
_controller.WithCallTo(c => c.RedirectToActionWithNoParameters())
103+
.ShouldRedirectTo(c => c.ActionWithNoParameters);
103104

104105
I can explicitly define whatever signatures I want to allow this terser syntax, but obviously the different permutations that are possible are mind-boggling and it wouldn't be helpful for any custom types in your project. Unfortunately, despite best efforts I couldn't figure out a way to generically specify these definitions - if anyone has ideas for how to do this let me know!
105106

@@ -109,16 +110,147 @@ If you have 1-3 parameters being passed into the action being redirected to then
109110

110111
Then you can write the following test for the redirect:
111112

112-
_controller.WithCallTo(c => c.Index()).ShouldRedirectTo<string, int, bool>(c => c.SomeAction)
113+
_controller.WithCallTo(c => c.Index())
114+
.ShouldRedirectTo<string, int, bool>(c => c.SomeAction);
113115

114116
If you have more than three parameters, or you are uncomfortable with that syntax then you can specify a lambda with a call to the action you want and pass in dummy values for the parameters, e.g. for the previous example:
115117

116-
_controller.WithCallTo(c => c.Index()).ShouldRedirectTo(c => c.SomeAction(null, 0, false))
118+
_controller.WithCallTo(c => c.Index())
119+
.ShouldRedirectTo(c => c.SomeAction(null, 0, false));
117120

118121
You can also pass through a MethodInfo object against the method you are redirecting to, e.g.:
119122

120-
_controller.WithCallTo(c => c.Index()).ShouldRedirectTo(typeof(HomeController).GetMethod("SomeAction"))
123+
_controller.WithCallTo(c => c.Index())
124+
.ShouldRedirectTo(typeof(HomeController).GetMethod("SomeAction"));
121125

122126
If you use this option (I don't recommend it because it uses a "magic" string so if you change the action name then the string won't change, although at least the test will break because the Method name will no longer be valid; in saying that if you change your parameters more often than the action name this might be a better option) be careful that you don't get an AmbiguousMatchException if there are multiple actions with that name.
123127

124128
At this stage there isn't support for the `[ActionName()]` attribute or simply passing through a string to check against the action name, but if either are important to you feel free to add an issue for this GitHub project and I can add them.
129+
130+
### Redirect to action in another controller
131+
132+
If you are redirecting to an action in another controller, then there are two syntaxes that you can currently use (similar to the last two mentioned above):
133+
134+
_controller.WithCallTo(c => c.Index())
135+
.ShouldRedirectTo<SomeOtherController>(typeof(SomeOtherController).GetMethod("SomeAction"));
136+
137+
_controller.WithCallTo(c => c.Index())
138+
.ShouldRedirectTo<SomeOtherController>(c2 => c2.SomeAction());
139+
140+
### View results (where the view name is the same as the action name - explicitly or via an empty string)
141+
142+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView();
143+
144+
// Or, if you want to check a partial is returned
145+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultPartialView();
146+
147+
### View results
148+
149+
_controller.WithCallTo(c => c.Index()).ShouldRenderView("ViewName");
150+
151+
// Or, if you want to check a partial is returned
152+
_controller.WithCallTo(c => c.Index()).ShouldRenderPartialView("ViewName");
153+
154+
Unfortunately, I couldn't think of a way to get rid of the magic strings here so where possible use the default ones above.
155+
156+
See below for model testing.
157+
158+
### Files
159+
160+
_controller.WithCallTo(c => c.Index()).ShouldRenderFile();
161+
162+
_controller.WithCallTo(c => c.Index()).ShouldRenderFile("content/type");
163+
164+
### Http status codes
165+
166+
_controller.WithCallTo(c => c.Index()).ShouldGiveHttpStatus();
167+
168+
_controller.WithCallTo(c => c.Index()).ShouldGiveHttpStatus(404);
169+
170+
### JSON
171+
172+
_controller.WithCallTo(c => c.Index()).ShouldReturnJson();
173+
174+
_controller.WithCallTo(c => c.Index()).ShouldReturnJson(data =>
175+
{
176+
/* Assertions on the data being turned into json (data) */}
177+
);
178+
179+
### Model tests
180+
181+
If you assert that the action returns a view of some sort there are some other methods that you can call (seen easily using intellisense). These allow you to check the model, e.g.:
182+
183+
// Check the type of the model
184+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
185+
.WithModel<ModelType>();
186+
187+
// Check that a particular object was passed through as the model
188+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
189+
.WithModel(expectedModel);
190+
191+
// Check that the model that was return passes a predicate
192+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
193+
.WithModel<ModelType>(m => m.Property1 == "hello");
194+
195+
// Make assertions on the model
196+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
197+
.WithModel<ModelType>(m => {/* Make assertions on m */});
198+
199+
Note: if you use any of these model tests then it will check that the model passed through isn't null.
200+
201+
### Model error tests
202+
203+
Once you have made assertions about the model you can then make assertions that particular model errors are present for properties of that model. While it's not generally the best idea to add validation logic to controllers ([doing it unobtrusively is best](http://robdmoore.id.au/blog/2012/04/27/unobtrusive-validation-in-asp-net-mvc-3-and-4/)), sometimes it's useful.
204+
205+
// Check that there are no model errors
206+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
207+
.WithModel<ModelType>().WithNoModelErrors();
208+
209+
// Check that there is a model error against a given property in the model
210+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
211+
.WithModel<ModelType>().AndModelErrorFor(m => m.Property1);
212+
213+
// Check that there is a model error against a specific key
214+
// Avoid if possible given it includes a magic string
215+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
216+
.WithModel<ModelType>().AndModelError("Key");
217+
218+
// You can chain these model error calls and thus check for multiple errors
219+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
220+
.WithModel<ModelType>()
221+
.AndModelErrorFor(m => m.Property1)
222+
.AndModelErrorFor(m => m.Property2);
223+
224+
You can also make assertions on the content of the error message(s); these methods will look for any error messages against that particular model state key that match the given criteria:
225+
226+
// Equality
227+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
228+
.WithModel<ModelType>().AndModelErrorFor(m => m.Property1)
229+
.ThatEquals("The error message.");
230+
231+
// Start of message
232+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
233+
.WithModel<ModelType>().AndModelErrorFor(m => m.Property1)
234+
.BeginningWith("The error");
235+
236+
// End of message
237+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
238+
.WithModel<ModelType>().AndModelErrorFor(m => m.Property1)
239+
.BeginningWith("message.");
240+
241+
// Containing
242+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
243+
.WithModel<ModelType>().AndModelErrorFor(m => m.Property1)
244+
.Containing("e error m");
245+
246+
You can chain the error property checks after any of these checks (you can only perform one of the checks though):
247+
248+
_controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView()
249+
.WithModel<ModelType>()
250+
.AndModelErrorFor(m => m.Property1).ThatEquals("The error message.")
251+
.AndModelErrorFor(m => m.Property2);
252+
253+
Any questions, comments or additions?
254+
--------------------------
255+
256+
Leave an issue on the GitHub project or a comment on my [blog](http://robdmoore.id.au). Also, feel free to send through a pull request.

0 commit comments

Comments
 (0)