我有一个用于基本 CMS 系统的 HTML Helper,它为特定内容对象调用 Controller 和操作。一个简化的例子如下:
public static MvcHtmlString RenderCMSObject(this HtmlHelper helper, CMSObject cmsObject)
{
var actionName = string.IsNullOrEmpty(cmsObject.ActionName)
? "Index"
: cmsObject.ActionName;
var controllerName = string.IsNullOrEmpty(cmsObject.ControllerName)
? "Default"
: cmsObject.ControllerName;
return helper.Action(actionName, controllerName);
}
如何对它进行单元测试?
我可以创建一个 HtmlHelper,并模拟它的某些方面(例如 ViewBag)来测试返回字符串的 HTML 帮助程序(例如)。
对于上面的示例,它只需要一个可以模拟 Action 方法以返回特定内容的测试,这样就可以断言它是用正确的参数调用的。
深入研究 Action 的源代码,看起来测试必须是更复杂的集成测试和模拟路由、网络请求和 Controller 本身。
最佳答案
没有简单的方法来测试 helper.Action 是否调用了正确的参数。这是因为正如一些评论所指出的那样,HtmlHelper 也不是可模拟的,而 Action 也是一个静态扩展。但是您可以使用变通方法测试特定场景,例如根据您的问题。
it simply requires a test that could mock the Action method to return something in particular so it can be asserted it's being called with the right parameters.
虽然由于静态性质这不太可能,但我们可以使用不同的技术来验证是否使用正确的参数调用了 Action。
这只是指南,我还没有完全测试我的代码。我知道它会在测试上下文中工作,但我不完全确定这会在生产代码执行期间产生正确的结果。如果没有,我很乐意再看一遍..
首先,我将创建一个允许我覆盖 helper.Action 方法的类。
public class HtmlHelperActionInvoker {
public virtual MvcHtmlString InvokeAction(HtmlHelper helper, string action, string controller) {
return helper.Action(action, controller);
}
}
然后在您的 Html 帮助程序类中,我将添加静态构造函数和一个委托(delegate)/函数,它允许我在测试执行期间设置我自己的 HtmlHelpActionInvoker 版本。
public static class SomeHtmlHelperClass
{
static SomeHelperClass() {
HtmlHelperActionFunc = () => new HtmlHelperActionInvoker();
}
public static Func<HtmlHelperActionInvoker> HtmlHelperActionFunc { get; set; }
public static MvcHtmlString RenderCMSObject(this HtmlHelper helper, CMSObject cmsObject)
{
var actionName = string.IsNullOrEmpty(cmsObject.ActionName)
? "Index"
: cmsObject.ActionName;
var controllerName = string.IsNullOrEmpty(cmsObject.ControllerName)
? "Default"
: cmsObject.ControllerName;
var helperAction = HtmlHelperActionFunc();
return helperAction.InvokeAction(helper, actionName, controllerName);
}
}
我相信静态 ctro 会执行一次,并在生产代码执行期间设置一次 HtmlHelperActionInvoker 的实例。后续请求将重用此实例。 (正如我之前提到的,您可能需要对此进行更多测试)
现在是单元测试
我们将使用一种称为 Extract & Override 的技术.
在您的测试区域中创建 HtmlHelperActionInvoker 的可测试版本。这不是假对象/ stub /模拟。这是 HtmlHelperActionInvoker 的可测试版本。并且仅用于使用预期参数调用的方法。
public class TesatableHtmlHelperAction : HtmlHelperActionInvoker
{
public string Controller { get; set; }
public string Action { get; set; }
public override MvcHtmlString InvokeAction(HtmlHelper helper, string action, string controller) {
Action = action;
Controller = controller;
return new MvcHtmlString("");
}
}
在单元测试中,我们将设置可测试的 TesatableHtmlHelperAction,以便 SUT(被测系统)执行可测试版本。 (注意:它仍然被认为是真实的,因为我们覆盖了真实 HtmlHelperActionInvoker 的行为)
[TestMethod]
public void HtmlHelperActionRenderCMSObject_Execute_EnsureInvokeActionCalledWithExpectedControlerAndActionName()
{
//Arrange
var fakecmsObject = new CMSObject() { ActionName = "foo", ControllerName = "bar" };
var testableHtmlHelperAction = new TesatableHtmlHelperAction();
SomeHelperClass.HtmlHelperActionFunc = () => testableHtmlHelperAction;
// Act
SomeHelperClass.RenderCMSObject(null, fakecmsObject);
// Verify
Assert.AreEqual<string>(fakecmsObject.ActionName, testableHtmlHelperAction.Action);
Assert.AreEqual<string>(fakecmsObject.ControllerName, testableHtmlHelperAction.Controller);
}
关于c# - 如何对调用 Action 的 HTML Helper 进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20011394/