今天下午我花了更好的时间试图弄清楚如何模拟(使用MOQ)相关的点点滴滴来对下面的HtmlHelper进行单元测试,用户在UrlHelper类中创建img标签:
public static IHtmlString Image(this HtmlHelper helper, string id, string url, string alternateText, object htmlAttributes)
{
// Instantiate a UrlHelper
var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
// Create tag builder
var builder = new TagBuilder("img");
// Create valid id
builder.GenerateId(id);
// Add attributes
builder.MergeAttribute("src", urlHelper.Content(url));
builder.MergeAttribute("alt", alternateText);
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
// Render tag
return new MvcHtmlString(builder.ToString(TagRenderMode.SelfClosing));
}
有没有人在他们的工作中解决过这个问题?
答案 0 :(得分:1)
您应该测试最终结果。如果你知道你的助手应该重新出现类似的话,那就说:
<img src="test.jpg" id="testId" alt="something" />
然后你的断言应该是通过将这个字符串与实际结果进行比较。你不应该在意它是否在内部使用帮助器。
答案 1 :(得分:1)
当我遇到非单元测试友好的.NET类型时,我通常编写自己的接口(只有我需要的方法)和实现接口的shim类,它只是将方法/属性调用转发给原始类。垫片可通过检查测试。
然后我编写了针对此接口进行单元测试所需的所有代码(因此我依赖于抽象,而不是具体结果)。这包括扩展方法,它扩展了接口而不是原始的具体类型。在这方面,测试扩展方法就像new Mock<IHtmlHelper>() ...
一样简单 - 你可以让IHtmlHelper
做任何你喜欢的事情,因为你可以在单元测试中完全控制它的行为。
键入接口和垫片对于具有较大接口的类来说有点乏味,但大多数情况下我发现开销非常低。这也意味着我最终会做更少的奇怪技巧来使事情变得可测试,因此我的代码更加一致且易于遵循(依赖性总是以相同的方式注入,测试总是以相同的方式编写)。
我认为Husein Roncevic正在做的一点是,你应该在可观察状态而不是行为方面测试HtmlHelper
的客户。换句话说,客户端代码的单元测试不应该知道调用了哪些方法(扩展方法或其他方法)。听起来你想对扩展方法本身进行单元测试,这是一件非常合理的事情。