Как вы, Moq.resx, который живет в App_GlobalResource?

Я пишу модульные тесты для контроллера в веб-проекте MVC3, но мои тесты выдают исключения, когда они пытаются получить доступ к ресурсу, например так:

return Index(Resources.Strings.MyStringResource);

Ресурс является .resx файл под названием Strings,

Я использую библиотеки Moq для выполнения модульного теста для HttpContextBase функциональность, поэтому мне было интересно, как я буду использовать библиотеки Moq для доступа к App_GlobalResource.

Любая помощь или указатели будут с благодарностью!

3 ответа

Решение

Вы не можете, по крайней мере, не напрямую. Классы со строгой типизацией, которые генерируются из файлов ресурсов (.resx), предоставляют статические методы, а не экземпляры.

Из-за этого они не могут реализовать метод интерфейса и не являются виртуальными; Moq требует, чтобы хотя бы одно из этих условий было выполнено, чтобы создать макет.

Чтобы обойти это, вы должны создать абстракцию, как и все остальное:

public interface IResources
{
    string MyStringResource { get; }
}

Вы передадите (или внедрите) реализацию этого в свой контроллер, а затем передадите это своему Index метод. Эта реализация может выглядеть примерно так:

public class ResourcesWrapper : IResources
{
    public string MyStringResource 
    { 
        get 
        { 
            return Resources.Strings.MyStringResource; 
        } 
    }
}

Затем, когда вы тестируете, вы можете использовать Moq для создания макета IResources интерфейс, и передать это вашему контроллеру, вот так:

// Create the mock.
var mock = new Mock<IResources>();

// Setup the property.
mock.SetupProperty(m => m.MyStringResource, "My Mocked Value");

// Pass the object somewhere for use.
Assert.AreEqual(mock.Object.MyStringResource, "My Mocked Value");

Итак, после реализации casperOne я столкнулся с другой ошибкой:

Мне подарили IOException заявив:

"Could not load file or assembly 'App_GlobalResources' or one of its dependencies. The system cannot find the file specified.":"App_GlobalResources"

Скотт Аллен предоставил причину и неотъемлемое решение этой проблемы.

Так что я сделал новый файл ресурсов в новой папке с именем "TResources" в моем веб-проекте, названный "TResources" исключительно потому, что это папка ресурсов, которая создается и используется только для целей тестирования (умно, а?)

Затем я изменил свойства моего ResourcesWrapper класс, чтобы вернуться TResources.Strings.MyStringResource скорее, чем Resources.Strings.MyStringResource,

ПРИМЕЧАНИЕ: свойства в IResources интерфейс не должен быть доступен только для чтения, так как при настройке фиктивного объекта, если свойство доступно только для чтения, произойдет сбой, так как значение не может быть установлено.

Следовательно, IResources должно выглядеть примерно так:

public interface IResources
{
    string MyStringResource { get; set; }
}

ResourcesWrapper затем следует реализовать IResources как это:

public class ResourcesWrapper : IResources
{
    public string MyStringResource 
    { 
        get 
        { 
            return TResources.Strings.MyStringResource; 
        } 
        set
        {
            //do nothing
        }
    }
}

Таким образом, вы сможете успешно выполнить макет в модульном тесте, например так:

var mock = new Mock<IResources>();
mock.SetupProperty(m => m.MyStringResource, "");

ПРИМЕЧАНИЕ. Вам не нужно ничего указывать в initialValue Параметр метода выше, так как свойство будет возвращать значение, полученное из Strings.resx,

На этом мой вопрос заканчивается, я надеюсь, что это может быть полезным для кого-то еще в интернете!

Этот ответ Darin Dimitrov на аналогичный вопрос переполнения стека дает гораздо более простой подход. Все дело в изменении свойств файла Resources.resx для поддержки модульного тестирования.

Другие вопросы по тегам