单元测试模拟Url.Action



我正在使用Moq框架编写单元测试,我有一个返回

的控制器函数
return Json(new
{    
    redirectUrl = Url.Action("Action", "Controller"),
    isredirection = true
});

我希望能够在redirectUrl中测试结果,但不知道如何在Mock中测试Url.Action.,我如何设置,以便我可以指定Url.Action("Action", "Controller")是否被称为返回这个?

你不能。关于模拟有一个很容易记住的规则——不能重写,不能模拟1。如果你是从Url类派生的,你能重写Action方法吗?不。也不能Moq, Rhino, FakeItEasy或任何其他基于DynamicProxy的框架。

您的选项缩小以下选项:

  • 使用不同的框架,而不是基于DynamicProxy(这通常意味着基于编译器服务进行高级拦截)-这些工具通常是付费的。
  • 用接口/委托包装有问题的调用,并将其注入测试代码(以便您可以使用免费框架模拟它)

包装会是什么样子?

public interface IUrlWrapper
{
    string Action(string name, object values);
}
// Wrapper Interface
public class TestedClass
{
    private readonly IUrlWrapper url;
    public TestedClass(IUrlWrapper urlWrapper)
    {
        this.url = urlWrapper;
    }
    // ...
    return Json(new
    {
        redirectUrl = this.url.Action("Action", "Controller"),
        isredirection = true
    });
    // ...
}

有了这样的设置,您可以使用Moq,而不会出现进一步的问题。但是,在单个方法调用中,您也可以使用Func委托,而不需要任何隔离框架:

// Func Delegate
public class TestedClass
{
    private readonly Func<string, object, string> urlAction;
    public TestedClass(Func<string, object, string> urlAction)
    {
        this.urlAction = urlAction;
    }
    // ...
    return Json(new
    {
        redirectUrl = this.urlAction("Action", "Controller"),
        isredirection = true
    });
    // ...
}

在您的测试中,您只需动态地创建委托。


1我写了一篇博客文章,详细介绍了这个问题:如何用…

模拟私有方法

最新更新