I've seen people testing that RenderView is called by a controller by inheriting into a "testable" controller. Madness!
RenderView is just a convenience method that calls to IViewEngine, so why not just test expectations on that with a mock? We basically want to test that the correct ViewContext is sent to the RenderView method of the view engine.
This is my test:
[TestFixture]
public class HomeControllerTests : ControllerTestsBase<HomeController>
{
public override HomeController CreateController()
{
return new HomeController();
}
[Test]
public void Renders_Index()
{
var render = ExpectRenderView();
Controller.Index();
Assert.That(render.Data.ViewName, Is.EqualTo("Index"));
}
}
I don't think we can get more straight forward than that!
This is my test base class:
(I'm using Moq as the mock framework.)
public abstract class ControllerTestsBase<T>
where T : Controller
{
public T Controller;
public Mock<IViewEngine> ViewEngine;
[SetUp]
public virtual void SetUp()
{
Controller = CreateController();
ViewEngine = new Mock<IViewEngine>();
Controller.ViewEngine = ViewEngine.Object;
Controller.ControllerContext = new Mock<ControllerContext>(new Mock<HttpContextBase>().Object, new RouteData(), Controller).Object;
}
public abstract T CreateController();
public RenderCall<ViewContext> ExpectRenderView()
{
var render = new RenderCall<ViewContext>();
ViewEngine.Expect(v => v.RenderView(It.IsAny<ViewContext>()))
.Callback(new Action<ViewContext>(render.Set));
return render;
}
}
The RenderCall class provides a place to receive the view context that is passed.
public class RenderCall<T>
{
bool _called;
T _data;
public T Data
{
get
{
if (!_called) throw new InvalidOperationException("View was not rendered.");
return _data;
}
}
public void Set(T data)
{
_data = data;
_called = true;
}
}