Update: I have put up a new post here that shows how I have simplified some of my testing. If you like it please kick it so that others will see the follow up post!
Here is my "Update" action on a project that I am working on:
public void Update(int id)
{
_viewData.User = _userRepository.GetUser(id);
BindingHelperExtensions
.UpdateFrom(_viewData.User, Request.Form);
_userRepository.SubmitChanges();
RedirectToAction("List");
}
And here is my test for it (using Moq, I wanted to try it out. This uses the Moq MvcMockHelpers from Scott Hanselman's post):
public void UserControllerUpdateTest()
{
RouteTable.Routes.Add(
new Route("[controller]/[action]", new MvcRouteHandler()));
var mockUserRepository = new Mock<IUserRepository>();
var user = new User()
{
Id = 10,
UserName = "TestUser",
EmailAddress = "test@test.com",
ModifiedOn = DateTime.Now,
CreatedOn = DateTime.Now
};
mockUserRepository.Expect(ur => ur.GetUser(10))
.Returns(user);
mockUserRepository.Expect(ur => ur.SubmitChanges());
var fakeController =
new UserControllerForTesting(mockUserRepository.Object);
FakeViewEngine fakeView = new FakeViewEngine();
fakeController.ViewEngine = fakeView;
var context = new MockHttpContextContainer();
var formData = new NameValueCollection();
var userNameFormData = "TestUser2";
var emailAddressFormData = "test2@test.com";
formData.Add("User.UserName", userNameFormData);
formData.Add("User.EmailAddress", emailAddressFormData);
context.Request.Expect(r => r.Form)
.Returns(formData);
var routeData = new RouteData();
routeData.Values.Add("Action", "Add");
routeData.Values.Add("Controller", "Home");
fakeController
.SetFakeControllerContext(context.Context.Object,
routeData);
fakeController.Update(10);
mockUserRepository.VerifyAll();
Assert.AreEqual(fakeController.RedirectedAction, "List");
var viewData = fakeController.TestingViewData;
Assert.IsNotNull(viewData);
Assert.IsNotNull(viewData.User);
Assert.AreEqual(viewData.User.UserName,
userNameFormData);
Assert.AreEqual(viewData.User.EmailAddress,
emailAddressFormData);
}
And that doesn't even include any of my helper objects or methods. Anyone see a problem with this? I am going to have to put some serious effort into streamlining this. I know that there is quite a bit I can abstract out across different controllers and actions so we will see how this goes. Feel free to provide feedback if you like. So far though I am really having fun digging into this, I can't believe I waited this long!