Модульный тестовый макет Url.Action

Я пишу модульный тест, используя структуру Moq, и у меня есть функция контроллера, которая возвращает

return Json(new
{    
    redirectUrl = Url.Action("Action", "Controller"),
    isredirection = true
});

Я хочу иметь возможность проверить результат в redirectUrl, но не знаю, как Mock Url.Action. Как я могу настроить, чтобы я мог указать, вызывается ли Url.Action("Action", "Controller"), вернуть это?


person user473104    schedule 07.03.2013    source источник
comment
Обычная практика - обернуть статические классы и методы расширения, подобные этим, в инстансированную оболочку, которая внедряется в контроллер, которую вы, в свою очередь, можете имитировать.   -  person J. Steen    schedule 07.03.2013
comment
stackoverflow.com/questions/2387155/unit-test-url-action Я использовал код из этот вопрос. В ответе нет кода, но в вопросе показан пример настройки свойства Controller.Url. По крайней мере, Url.Action не вызывал исключения в моих модульных тестах после того, как я последовал этому примеру.   -  person 2b77bee6-5445-4c77-b1eb-4df3e5    schedule 23.04.2019


Ответы (1)


Вы не можете. Легко запомнить правило насмешки - не может отменять, не может издеваться 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 Я написал сообщение в блоге, в котором более подробно рассказывается об этой самой проблеме: Как имитировать частный метод с помощью ...

person k.m    schedule 07.03.2013